JS-201-ReactFundamentals
  • Part 0: App Overview
  • Part 1: Intro to React
    • 1.0: Packages Setup
    • 1.1: Project Setup
    • 1.2: React Router Dom
  • Part 2: JavaScript Concepts
    • 2.0: ES6 Overview
    • 2.1: classes
    • 2.2: constructors
    • 2.3: extends
    • 2.4: super
    • 2.5: interpolation
    • 2.6: map
    • 2.7: filter
  • Part 3: Functional Components
    • 3.0: Functional Components Overview
    • 3.1: Calling Functional Components
    • 3.2: Single Element Rule
    • 3.3: Arrow Functions
    • 3.4: Challenge
    • 3.4: Solution
    • 3.5: Challenge 2
    • 3.5: Solution 2
  • Part 4: JSX Challenge
    • 4.1: JSX Overview
    • 4.1: Challenge Answer
    • 4.2: className
  • Part 5: Class Concepts
    • 5.1: State
    • 5.2: setState
    • 5.3: Class Components Challenge
    • 5.4: Class Components Challenge Answer
  • Part 6: Props Starter
    • 6.0: Props Overview
    • 6.1: Props Demo and Challenge 1
    • 6.2: Props Answer 2
    • 6.3: Props Passing Functions and Challenge 2
    • 6.4: Props Answer 2
    • 6.5: External Props and Mapping Components
    • 6.6: PropTypes
  • Part 7: Lifecycle Methods
    • 7.0: Lifecycle Overview
    • 7.1: Lifecycle Methods
    • 7.2: Mounting Methods
    • 7.3: Update Methods
    • 7.4: Unmount Methods
  • Part 8: Apps
    • 1.0 - Small Timer Apps
      • 1.1 - Simple Timer
      • 1.2 - Clock App
      • 1.3 - Stop Watch App
      • 1.4 - Challenge
    • 2.0 - Concept List
      • 2.1 - Concept Data
      • 2.2 - Concept App Component
      • 2.3 - Concept Component
      • 2.4 - Concept List Component
    • 3.0 - NYT
      • 3.1 - NytApp Component
      • 3.2 - Nyt Results
    • 4.0 - The Friend List App
      • 4.1 - Friend List App Component
      • 4.2 - Friend Component
    • 5.0 - Movie Search Application
      • 5.1 - Form Component
      • 5.2 - Form Results Component
      • 5.3 - Styled Components
    • 6.0 - YouTube Api
      • 6.1 - Video Component
      • 6.2 - Video Component
      • 6.3 - Video Component
    • 7.0 - Github Api Application
      • 7.1 - The Users
      • 7.2 - Github API Component
      • 7.3 - Github API Card
      • 7.4 - Github API Card Form
      • 7.5 - Github API Card List
      • 7.6 - Github API Search
      • 7.7 - Github API Challenge
    • 8.0 - Bitcoin Api Application
      • 8.1 - Bitcoin API Setup
      • 8.2 - Bitcoin API Fetch
      • 8.3 - Bitcoin API Line Chart
      • 8.4 - Bitcoin API Fetching Data
      • 8.5 - Bitcoin API Info Box
      • 8.6 - Bitcoin API Completed Code
    • 9.0 - Google Maps Api Challenge
    • 10.0 - Sound Cloud App Challenge
    • 11.0 - VR App Challenge
    • 12.0 - React Native Intro
  • Part 9: Project
  • Part 10: Notes
    • 10.1 - Resources
    • 10.2 - Troubleshooting
Powered by GitBook
On this page
  • Planning and Thinking about What We are Building
  • Setting up our Component
  • Setting Up the State
  • API URL & Key
  • Making API Calls
  • Creating a Form
  • Creating Methods for Submit and Change
  • Updating our Render
  1. Part 8: Apps
  2. 3.0 - NYT

3.1 - NytApp Component

Planning and Thinking about What We are Building

So, we know what we are trying to build, as we've already built it in vanilla JS. We need to build a page that fetches information from the NYT API when a user submits a form. Then we're going to display that information nicely to the screen. In Vanilla JS we needed to create an HTML file and a JS file. In React we can, of course, just do JSX. We used about 190 lines of code in our vanilla JS, and here we'll do around 100, not that lines of code is super important. However, our React code should be much more readable and easy to refactor. Since we know what we'll need to build, we can think about what kind of components we'll want. We'll definitely need our parent component (NytApp) to handle the data, and then we should probably make a separate component to display information. You can always break them down more if it makes sense to you.

Setting up our Component

import React, { Component } from 'react';
export default class NytApp extends Component {
  constructor(props) {
    super(props)
    this.state = {}
  }
  render(){
      return(
        <div className="main">
            <div className="mainDiv">
            </div>
        </div>
      )
  }
}

Since this is our parent component for this mini-application, we'll be handling the storing of information here, hence why we'll need to use state. For now, we can set it up as an empty state while we think about what we'll need to store. When looking at the vanilla JS version of this app, we see that we created a LOT of variables at the beginning. For our state, we'll be using some of the same ones to keep information, but we don't need as many as we needed in vanilla JS.

Setting Up the State

Thinking about state first is a good way to organization your application. When we think about what data we need to store, use, and change, we can think about what we want to put in our state to allow us to do that. For our NYT app, we need to store the information from the user, the search term, the start date and the end date, so we can send these to our API, so we'll need to create those in the state. We also want to capture the results from our API, so we can call that 'results', and we want to keep track of our page number. Let's fill out our state like below.

constructor(props) {
    super(props)
    this.state = {
      search: '',
      startDate: '',
      endDate: '',
      pageNumber: 0,
      results: []
    };
  }

That should take care of all the data we need to store that can change depending on how the user interacts with our application. We also have a couple of other things we need to store in variables and use, but these things will not change as the user interacts with our application, so we can declare them as consts.

API URL & Key

Since our base API url and the API key won't change as the users interact with the application we can declare them as consts outside of our class component. Make sure you use the same API key you created before for the NYT application. Below your import statement and above your export class ... statement, declare the following consts.

const baseURL = 'https://api.nytimes.com/svc/search/v2/articlesearch.json';
const key = 'yourKeyHereabc123def456ghi789jkl0';

Making API Calls

So, now that we have our baseURL and API key set up, we can start to set up our fetch. We're going to create a method that will fetch results for us, and we can call this when we need to (when the user submits the form, when the user presses next or previous page, etc.). Underneath and outside of the constructor, but before the render, write the following method.

fetchResults = () => {
    let url = `${baseURL}?api-key=${key}&page=${this.state.pageNumber}&q=${this.state.search}`
    url = this.state.startDate ? url + `&begin_date=${this.state.startDate}` : url
    url = this.state.endDate ? url + `&end_date=${this.state.endDate}` : url
    fetch(url)
      .then(
        (response) => response.json()
      ).then((data) => {
        this.setState({ results: data.response.docs })
      })
  }

Let's break down what we are doing in fetchResults.

1) First thing, is notice that we are using an arrow function here. In react, this means that we do not have bind this method, because arrow functions do not create their own this, therefore they use their parent's this. If we hadn't used an arrow function here, we would need to bind this function to this in the constructor, in order to be able to use this.setState or this.state.

2) Second, we are creating our url variable based on the baseURL, the key, and also the pageNumber and search which we stored in the state. We'll worry about how to update those variables based on inputs later, for now we know we want to send whatever is in the state in our GET request.

Creating a Form

Cool so now we have set up our fetchResults, we need to actually be able to change the information in our state when our user interacts with our application. So far we have nothing in our render for our user to be able to interact with, so let's work on that now. Just like in vanilla JS, we can use a form to capture input from our user. Let's make our render function look like this:

render() {
    return (
      <div className="main">
        <div className="mainDiv">
          <form onSubmit={}>
            <span>Enter a SINGLE search term (required): </span>
            <input type="text" name="search" onChange={} required /><br />
            <span>Enter a start date: </span>
            <input type="date" name="startDate" pattern="[0-9]{8}" onChange={} /><br />
            <span>Enter an end date: </span>
            <input type="date" name="endDate" pattern="[0-9]{8}" onChange={} /><br />
            <button className="submit">Submit search</button>
          </form>
        </div>
      </div>
    );
  }

To make this form, we actually grabbed the form from the vanilla JS code, and just condensed it down a bit. We also added a couple of things that are specific to react, specifically the onSubmit and onChange. These are named pretty accurately for what they do. onSubmit does whatever you tell it to on submit of the form, and onChange does whatever you tell it to when a change happens in the input. We haven't done anything in these yet, so that'll be our next step.

Creating Methods for Submit and Change

So we need two methods to create, one for when the user submits the form, and one for when they type something into the inputs. Let's start with the form submit method. Let's put this function directly below and outside of the constructor.

  handleSubmit = (event) => {
    this.fetchResults()
    event.preventDefault()
  }

Let's break this method down. We're taking in an event, and then calling the fetchResults function. We're also calling event.preventDefault() which if you remember from vanilla JS, just prevents the default action, which in this case is the page refreshing, which we definitely do not want in react. That's really it. Next, let's look at how we can take the input from a user, and use it to set the state correspondingly. Type this method below your handleSubmit and above the fetchResults method.

  handleChange = (event) => {
    this.setState({
      [event.target.name]: event.target.value,
    });
  }

Updating our Render

Now, we need to update our render to actually use the methods we created. Make your render look like the following:

render() {
    return (
      <div className="main">
        <div className="mainDiv">
          <form onSubmit={e => this.handleSubmit(e)}>
            <span>Enter a SINGLE search term (required): </span>
            <input type="text" name="search" onChange={this.handleChange} required /><br />
            <span>Enter a start date: </span>
            <input type="date" name="startDate" pattern="[0-9]{8}" onChange={this.handleChange} /><br />
            <span>Enter an end date: </span>
            <input type="date" name="endDate" pattern="[0-9]{8}" onChange={this.handleChange} /><br />
            <button className="submit">Submit search</button>
          </form>
        </div>
      </div>
    );
  }

Before moving to the next step, check your code against the code below, it should look like this:

import React, { Component } from 'react';

const baseURL = 'https://api.nytimes.com/svc/search/v2/articlesearch.json';
const key = 'yourKeyHere';

export default class NytApp extends Component {
  constructor(props) {
    super(props)
    this.state = {
      search: '',
      startDate: '',
      endDate: '',
      pageNumber: 0,
      results: []
    };
  }

  handleChange = (event) => {
    this.setState({
      [event.target.name]: event.target.value,
    });
  }

  handleSubmit = (event) => {
    this.fetchResults()
    event.preventDefault()
  }

  fetchResults = () => {
    let url = `${baseURL}?api-key=${key}&page=${this.state.pageNumber}&q=${this.state.search}`
    url = this.state.startDate ? url + `&begin_date=${this.state.startDate}` : url
    url = this.state.endDate ? url + `&end_date=${this.state.endDate}` : url
    fetch(url)
      .then(
        (response) => response.json()
      ).then((data) => {
        this.setState({ results: data.response.docs })
      })
  }

  render() {
    return (
      <div className="main">
        <div className="mainDiv">
          <form onSubmit={e => this.handleSubmit(e)}>
            <span>Enter a SINGLE search term (required): </span>
            <input type="text" name="search" onChange={this.handleChange} required /><br />
            <span>Enter a start date: </span>
            <input type="date" name="startDate" pattern="[0-9]{8}" onChange={this.handleChange} /><br />
            <span>Enter an end date: </span>
            <input type="date" name="endDate" pattern="[0-9]{8}" onChange={this.handleChange} /><br />
            <button className="submit">Submit search</button>
          </form>
        </div>
      </div>
    );
  }
}
Previous3.0 - NYTNext3.2 - Nyt Results

Last updated 7 years ago

3) The next two lines are utilizing ternary operators to append the startDate and endDate if they exist to the url that we're going to use in our GET request. If you're not familiar with ternary operators, check out the docs . Basically, it's a nicer way to write an if, but make sure to check out the docs for more examples.

4) Next, after we've made sure our URL contains everything we need, we actually do the fetch() GET request to url. When that promise resolves, we're then called .json() on it, and when that promise resolves, we can grab our data that we receive from the API, and save that information to the state. We already created our results array in the state to hold the information we get back, so the set this to our actual results, we can call this.setState({results: data.response.docs}). This sets results in our state, equal to what we've gotten back from our API. In order to the know the structure of the response we are getting, its advisable to do two things. 1) read the docs of the API to figure out how data should be returned, 2) console log the request before ever trying to set state to know what the actual format of the data that you're getting is.

This is a really simple method but it's doing a lot. Instead of having to grab a value from a specific id like in vanilla JS, if you remember getElementById (if you don't, look ), we don't have to do that here. By passing the event into the method, and they we can grab the name and the value from the event and use them to set state with. Important to note is that our state and our name in the input must match, otherwise this won't work. So if we changed startDate to startingDate in the state, we would have to change it correspondingly in the form, as "name".

Now, when we type in the input boxes we should see our state changing. You can check this by utilizing the React Dev Tools in Chrome. If you don't have them installed yet, check them out . When you navigate to the <NytApp> component in your react dev tools, and then type in the input boxes, you should see the state changing! When you submit with something in your input box, you should see the results state update with info from the API. Next, we need to do something with those results!

Next, we'll handle how to display our results, and deal with pages!

here
here
here
here
NytResults Component