How do I update the React state immediately?

The function I made, which is for updating the state, doesn't work perfectly.

I make a deep copy of my current state, which I modify, then I set the state to that modified copy. I decided to run a simple map on a copy and update the property for each object in the array, this will immediately change the state of the application and show the changes. (not shown in the code below, something I just tried)

But it doesn't work with the changes I really want to make in the copy. Since setState happens in async, I understand that changes do not happen immediately, how can I solve this? As the changes are visible when the function is run a second time, but I want this to happen on the first run. You can see a live demo of what I am creating at https://non.mpedersen.me/ if you want.

Function in App.js

addressSearch(address){
    console.log('firing search for distance. Origin is: ' + address)
    let origin = [address];
    const newStores = JSON.parse(JSON.stringify(this.state.stores))
    let service = new google.maps.DistanceMatrixService();

    newStores.map(store => service.getDistanceMatrix({
      origins: origin,
      destinations: store.addressapi,
      travelMode: 'DRIVING',
    }, result => {
      store.distance = result.rows["0"].elements["0"].distance.text.replace(/\Dkm/, '').replace(/,/,'.').replace(/\s/, '');
      store.duration = result.rows["0"].elements["0"].duration.text;
    }))

    newStores.sort((a,b) => a.distance - b.distance);
    this.setState({stores : newStores})
  }

      

+3


source to share


2 answers


This solved it :)



getDistanceMatrix = (address, store) => {
    return new Promise((resolve) => {
      let service = new google.maps.DistanceMatrixService();
      let origin = [address];
      service.getDistanceMatrix({
        origins: origin,
        destinations: store.addressapi,
        travelMode: 'DRIVING',
      }, result => {
        store.distance = result.rows["0"].elements["0"].distance.text.replace(/\Dkm/, '').replace(/,/,'.').replace(/\s/, '');
        store.duration = result.rows["0"].elements["0"].duration.text;
        resolve(store)
      })
    })
  }

  addressSearch(address){
    console.log('firing search for distance. Origin is: ' + address)
    const newStores = JSON.parse(JSON.stringify(this.state.stores))
    Promise.all(newStores.map(store => this.getDistanceMatrix(address, store))).then(newStore => {
      newStores.sort((a,b) => a.distance - b.distance);
      this.setState({stores : newStores})
    })
  }

      

0


source


You must setState

after completing all getDistanceMatrix

and your card. Since this function works async, you don't really get the completion function when you setState

. Completion happens on a different stack.

Promises are really great because they help you deal with scenarios like this. This is a very good question because it shows the nature of JS mechanisms (event loop).

Try this code, but know that I haven't tested / run it if you realize it will get you where you want to go:



  const getDistanceMatrix = (store) => {
    return new Promise((resolve) => {
      service.getDistanceMatrix({
        origins: origin,
        destinations: store.addressapi,
        travelMode: 'DRIVING',
      }, result => {
        store.distance = result.rows["0"].elements["0"].distance.text.replace(/\Dkm/, '').replace(/,/,'.').replace(/\s/, '');
        store.duration = result.rows["0"].elements["0"].duration.text;
        resolve(store)
      })
    })
  }

  addressSearch(address){
    console.log('firing search for distance. Origin is: ' + address)
    let origin = [address];
    const newStores = JSON.parse(JSON.stringify(this.state.stores))
    let service = new google.maps.DistanceMatrixService();

    Promise.all(newStores.map(getDistanceMatrix).then((newStores) => {
      newStores.sort((a,b) => a.distance - b.distance);
      this.setState({stores : newStores})
    })
  }

      

BTW, the install state is asynchronous after resolving a Promise can lead to errors if the host component is no longer mounted. This is actually a great reason for adopting a template like redux, it makes things like that easy!

+4


source







All Articles