Anthony Finix
Anthony Finix

Reputation: 1

Event after calling setState gives me previous state value

I am trying to create a search bar for my React.js app.

I have passed getSearch() method of app.js to child component navigation to retrieve the input value.

In getSearch() method there is setState({searchTerm:e.target.value}) which is the retrieved value, and then i am calling the fetchData() method of app.js right after the setState() withing getSearch().

in fetchData() method this.state.searchTerm is passed as body for fetch(), but as I enter something and click enter it gives me the previous value of this.state.searchTerm and not latest updated value which user inputs.

What am I doing wrong? I am pasting my app.js for review:

import React, { Component } from "react";
import { BrowserRouter, Route, Switch } from "react-router-dom";

import "./App.css";

import Navigation from "./components/Navigation";
import Sidebar from "./components/Sidebar";
import Game from "./components/games";
import Profile from "./components/Profile";
import NotFound from "./components/Notfound";

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      gameFetched: "false",
      searchTerm: ""
    };
  }
  getSearch = e => {
    if (e.key === "Enter") {
      this.setState({
        searchTerm: e.target.value
      });
      this.fetchIGBD()
    }
  };

  componentDidMount() {
    this.fetchIGBD();
  }

  render() {
    return (
      <div className="App">
        <BrowserRouter>
          <div>
            <Navigation getSearch={this.getSearch} />
            <div id="main-wrapper" className="d-flex">
              <Sidebar />
              <div id="content">
                <Switch>
                  <Route path="/" component={Game} exact />
                  <Route path="/profile" component={Profile} />
                  <Route component={NotFound} />
                </Switch>
              </div>
            </div>
          </div>
        </BrowserRouter>
      </div>
    );
  }

  fetchIGBD = () => {
    let url = "http://localhost:8080/api-v3.igdb.com/games";
    let data ="fields name,cover,first_release_date,genres.name,platforms.name,total_rating;limit 10;sort popularity;where total_rating > 80;where release_dates.platform = 6;";
    let search = "search '"+this.state.searchTerm+"';";
    if (search !== "") {
      data = data + search
      console.log(data)
    }
    fetch(url, {
      method: "POST",
      body: data,
      headers: {
        "Content-Type": "application/json",
        "user-key": "myid"
      }
    })
      .then(res => res.json())
      .then(json => console.log(json))
      .catch(error => console.log(error));
    this.setState({
      gameFetched: "true"
    });
  };
}

export default App;

Upvotes: 0

Views: 738

Answers (3)

Cognisun Inc
Cognisun Inc

Reputation: 446

Alternate way of calling fetchIGBD is to use callback of setState method.It will ensure that you get updated value of searchTerm.It will triggered after setState complete.

   getSearch = e => {
     if (e.key === "Enter") {
      this.setState({
        searchTerm: e.target.value
      },function(){
        this.fetchIGBD()
      }
     );
    
  }
};

Upvotes: 0

Umair Farooq
Umair Farooq

Reputation: 1833

You can use following:

this.setState({
  searchTerm: e.target.value
 }, () => { 
  this.fetchIGBD()
});

setState function is async which means it doesn't executes immediately.

Upvotes: 2

Gabriele Petrioli
Gabriele Petrioli

Reputation: 196246

If you need to use the state in your fetchIGBD method you need to call it in the callback parameter of the setState. That is required because setState is asynchronous.

  getSearch = e => {
    if (e.key === "Enter") {
      this.setState({
        searchTerm: e.target.value
      }, this.fetchIGBD);
    }
  };

or if you need to pass parameters to it

  getSearch = e => {
    if (e.key === "Enter") {
      this.setState({
        searchTerm: e.target.value
      }, ()=> this.fetchIGBD(params_here));
    }
  };

Upvotes: 1

Related Questions