Eric Schumann
Eric Schumann

Reputation: 119

React: Child component is passing it's state up to parent, but once parent has it, the parent is not updating its state

My issue here is that I have some values coming up from the SearchForm component. They're passing the correct value as arguments to the handleSearch function, but my call to setState does nothing. I've included console.logs to show what's stored in the variables. See comments in the code below.

Because my state is being passed from this component to the ResultList component as empty strings, the ResultList does not render correctly.

import React, { Component } from 'react';
import axios from 'axios';
import SearchForm from './components/search_form';
import ResultList from './components/results_list';

class App extends Component {
  constructor(props) {
    super(props);

    this.state = { category: '', term: '', results: [] };
    this.handleSearch = this.handleSearch.bind(this);
  }

  handleSearch(category, term) {

    //This is not setting the state!!!!!
    this.setState({ category, term });

    //The first two console.logs successfully log the arguments to this 
    function
    //The last two console.logs log empty strings even after the above 
    setState call.

    console.log("Received from form: " + category);
    console.log("Received from form: " + term);
    console.log("#################################");
    console.log(this.state.category);
    console.log(this.state.term);


    console.log('http://swapi.co/api/' + category + '/?search=' + term);
    axios.get('http://swapi.co/api/' + category + '/?search=' + 
term).then((response) => {
        let results = response.data.results;
        this.setState({ results });
        console.log(this.state.results);
    }).catch((error) => {
      console.log(error);
    });

  }

  render() {
    return (
      <div className="container panel panel-default">
        <SearchForm handleSearch={this.handleSearch}/>
        <ResultList results={this.state.results} category=
{this.state.category}/>
      </div>
    );
  }
}

export default App;

Upvotes: 0

Views: 518

Answers (2)

bhaskar sharma
bhaskar sharma

Reputation: 96

setState is not a synchronous function call, so calling setstate in the function might not update the state immediately. as from the documentation

setState() enqueues changes to the component state and tells React that this component and its children need to be re-rendered with the updated state. This is the primary method you use to update the user interface in response to event handlers and server responses. Think of setState() as a request rather than an immediate command to update the component. For better perceived performance, React may delay it, and then update several components in a single pass. React does not guarantee that the state changes are applied immediately

so console.log(this.state.category); console.log(this.state.term); will not log the updated state. but if you put these statements in render function, you will see the correct state being set in next render.

Read more on https://facebook.github.io/react/docs/react-component.html#setstate

Upvotes: 0

Tyler Sebastian
Tyler Sebastian

Reputation: 9448

I'll elaborate on what I said in my comment:

Component#setState defers and batches state update requests for performance. Because of this, you cannot relay on the Component.state to be updated with the new values immediately after the call.

setState provides a second argument - a callback which is called after the state update operation is performed. In your case, it would look like

this.setState({ category, term }, () => {
  console.log(this.state.term, this.state.category)
  // now you can use them
}) 

Upvotes: 2

Related Questions