0

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;
Eric Schumann
  • 119
  • 1
  • 1
  • 9

2 Answers2

2

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
}) 
Tyler Sebastian
  • 9,067
  • 6
  • 39
  • 62
  • i don't think even this works. The callback function will have the same state and not the updated state. If you want to use the new variables in callback, you will have to explicitely pass them in the function – bhaskar sharma Aug 18 '17 at 18:18
  • @bhaskarsharma I'm not sure I follow - what do you mean "if you want to use the new variables in the callback?" – Tyler Sebastian Aug 18 '17 at 18:21
  • @bhaskarsharma check [this answer](https://stackoverflow.com/a/42593250/5185595) :) – Mayank Shukla Aug 18 '17 at 18:24
  • let's say you want to use category and term in your callback function `() => { console.log(this.state.term, this.state.category) // now you can use them })` then this.state.term and this.state.category will not be the updated state variables but the same old variables, so you will have to pass new variables in your callback `(term, category) => { console.log(term, category) // now you can use them })` like this – bhaskar sharma Aug 18 '17 at 18:25
  • er, no... there are no arguments to the callback. – Tyler Sebastian Aug 18 '17 at 18:30
0

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