简体   繁体   中英

Updating State with Variable in React

I'm attempting to crack this particular nut where my state isn't updating. I've got a function calling the NASA api through Axios which is working fine. Currently the datePicked state is empty by default which means the GET request defaults to the current date. I'm to adding functionality to generate a random date (function onRandomDateClick ), which is all working fine.

Then I want to update the state of datePicked with the generated date, and then run the onImageGet function which holds the axios request.

Initial State

  class Photo extends Component {
    state = {
      apiUrl: 'XXXXXXXX',
      apiKey: 'XXXXXXXX',
      image: null,
      imgChecked: false,
      datePicked: ""
    };

Generates random Date, logs variable and state. State currently displays blank. this.setState isn't working.

    onRandomDateClick = (e) => {
      function randomDate(start, end) {
        return new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime()));
      }
      let randomDateResult = randomDate(new Date(2012, 0, 1), new Date())
      let datePicked = randomDateResult.toISOString().slice(0,10);
      this.setState({datePicked})
      console.log("variable is " + datePicked);
      console.log("state is " + this.state.datePicked);
      this.onImageGet();
    }

Axios call with state here

    onImageGet = e => {
      axios.get(`${this.state.apiUrl}?api_key=${this.state.apiKey}&date=${this.state.datePicked}`)
      //response always starts res.data
          .then(res => {
            const image = res.data;
            this.setState({ image })
          })
          this.setState({imgChecked: true})
    }


    render() {
      ...blah blah...
      return (
        <div className="photo">        

         ... blah blah blah ...
        </div>

      );
    }
  }

The problem is that setState is asynchronous so when you call onImageGet right after setting the state, the state has not yet been updated and you access the previous one.

You could use the callback method that setState supports which is called once the state has been updated.

this.setState({datePicked}, this.onImageGet)

or a more common pattern would be to check for relevant changes in the componentDidUpdate and call the this.onImageGet there.

  class Photo extends Component {
    state = {
      apiUrl: 'XXXXXXXX',
      apiKey: 'XXXXXXXX',
      image: null,
      imgChecked: false,
      datePicked: ""
    };


    onRandomDateClick = (e) => {
      function randomDate(start, end) {
        return new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime()));
      }
      let randomDateResult = randomDate(new Date(2012, 0, 1), new Date())
      let datePicked = randomDateResult.toISOString().slice(0,10);
      this.setState({datePicked})
      console.log("variable is " + datePicked);
      console.log("state is " + this.state.datePicked);
    }

    onImageGet = e => {
      axios.get(`${this.state.apiUrl}?api_key=${this.state.apiKey}&date=${this.state.datePicked}`)
      //response always starts res.data
          .then(res => {
            const image = res.data;
            this.setState({ image })
          })
          this.setState({imgChecked: true})
    }

    componentDidUpdate(prevProps, prevState){
      if (prevState.datePicked !== this.state.datePicked){
        this.onImageGet();
      }
    }

    render() {
      ...blah blah...
      return (
        <div className="photo">        
         ... blah blah blah ...
        </div>

      );
    }
  }

Js is working async for http call. for React setState is async.you should do something like this.

 onRandomDateClick = (e) => { function randomDate(start, end) { return new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime())); } let randomDateResult = randomDate(new Date(2012, 0, 1), new Date()) let datePicked = randomDateResult.toISOString().slice(0,10); this.setState({datePicked},() => { this.onImageGet(); }) } onImageGet = e => { axios.get(`${this.state.apiUrl}?api_key=${this.state.apiKey}&date=${this.state.datePicked}`) //response always starts res.data .then(res => { const image = res.data; this.setState({ image, imgChecked: true }) }) } render() { ...blah blah... return ( <div className="photo"> ... blah blah blah ... </div> ); } } 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM