Getting Started with React: Lesson 7 of 14

Parent-Child Component Communication

Up Next

Iterating Over Data

Autoplaying in 7 seconds!

Cancel

Now that we understand state and can manage the value of the input in state, we need a way to pass that back up to the App component. Another way to say this is we need a child to be able to talk and interact with its parent. To do this, however, the parent will also need to be able to pass data down to its child. Luckily, React makes this simple through a concept called "props."

Short for properties (I assume), props are data that are passed from a parent to its children and are made available through this.props on the child component. We have actually already seen some props. Every element we write in JSX is actually a wrapper around the creation of a real DOM element. Props are represented as attributes on the components in the JSX we write. So earlier when we passed value and onClick attributes, we were actually passing props to the underlying component!

Child-to-parent communication is a little more complicated. The standard way of doing this is to have the parent pass a function to the child through props. The child then calls this function at some point and passes it a value that the parent is supposed to react to. We then write the functionality for the parent's reaction inside the parent component.

Phew. Let's just write some code! We will write a method in the App component that receives a zipcode and saves it in it's own state.

onFormSubmit(zipcode) {
  this.setState({ zipcode });
}

Pretty easy. We have seen this. We know, though, that since we are changing state, we need to initialize our state in the constructor.

constructor(props) {
  super(props);

  this.state = {
    zipcode: '',
  };
}

Also, since we know that this method will get called after render is called, we need to bind this to the method. Add this at the botom of the constructor.

this.onFormSubmit = this.onFormSubmit.bind(this);

OK. Excellent! Now let's pass this through props to our ZipForm like so.

<ZipForm onSubmit={this.onFormSubmit} />

Notice, we have added a prop of onSubmit and passed it our method. We can then access this on the child as this.onSubmit. In the ZipForm component, we need to create a method that will react to a form submission by grabbing the value of the zipcode and passing it to the onSubmit prop method.

submitZipCode(e) {
  e.preventDefault();

  const { zipcode } = this.state;
  const { onSubmit } = this.props;

  onSubmit(zipcode);
}

We need to prevent the default action of the form so that we stay on the page. Then we pull the zipcode out of state and the onSubmit method out of props. Then we call onSubmit and pass it the zipcode. This is how the parent knows about the form submission.

Also, don't forget that we need to bind this in the ZipForm to this new method.

this.submitZipCode = this.submitZipCode.bind(this);

We are almost done. Last thing we need to do is make sure that the method we just made is called when the form is submitted. We do this by passing an onSubmit prop to our form element.

<form onSubmit={this.submitZipCode}>

That's it! Go to the browser and give it a try. Submit the form. Then open the React Dev Tools and look at the value of zipcode in the App component's state. It's updated!

One last thing. Notice that the value of the input isn't cleared out. It's not immediately obvious that the form was submitted. Let's empty that field out to show things worked to the user. At the bottom of the submitZipCode handler in the ZipForm component, we need to set the zipcode piece of state to an empty string.

this.setState({ zipcode: '' });

We did it! That wasn't so bad, huh?

Now that we are updating the zipcode in the App, let's use it to get weather data from our local API and save it in state. Update onFormSubmit to look like below.

onFormSubmit(zipcode) {
  get(`http://localhost:3000/weather/${zipcode}`)
  .then(({ data }) => {
    const { city, list: dates } = data;

    this.setState({ zipcode, city, dates, selectedDate: null });
  });
}

Import axios.get at the top of this file.

import { get } from 'axios';

Above, we are making a network call using axios to our local API. The API will return weather data from the zipcode we send it. Once that comes back, we pull data out of the response. We then deconstruct the data to pull out the pieces we need. We then update the internal state of our App with the new zipcode, city, dates, and set the selectedDate to null. selectedDate will eventually hold the index of the date we click on.

One last thing we need to do is make sure that we are initializing these new pieces of state in our constructor.

this.state = {
  zipcode: '',
  city: {},
  dates: [],
  selectedDate: null
};

That's it. View it in the browser, and you will see that nothing has changed. Anticlimatic. However, if you view the React Dev Tools, update the zipcode, and submit the form, you will see all the new data populated in the App component's state. We are killin' it!

We have all this data, but how do we get it on screen. Well, we already have all the tools to do this. Let's do it in the next one.

Alex Sears

2 posts

Developing is not only my job but also my passion. I love to teach myself new things as much as I love teaching others. The more people we get involved in this little thing we call "web development," the better we can make it. I mean, we always need more cat videos, right?