0

Currently I am fetching some data and I save the response via useState. The response is saved but the problem is the second fetch takes place before the state was saved making that value undefined.

I tried to do like this:

  useEffect(() => {
    fetchTrackingData().finally(() => {
      console.log("Destination", destination.coordinates);
      fetchDriverLocation().finally(() => {
        setLoading(false);
      });
    });
  }, []);

Basically fetchTrackingData function has destination coordinates which I save with:

const [destination, setDestination] = useState('');

In the fetchTrackingData function I am setting the state after receiving the response. After fetchTrackingData is done fetching and it has saved state of destination I then use finally() method and then call the second fetch which is fetchDriverLocation but it has destination undefined and even I logged to see if the value gets saved after finally() but it is undefined in log as well.

How can I store the value from one API in that API call and then use that value in another API call?

incredible123
  • 103
  • 11
  • Are you sure `fetchTrackingData` returns the data and sets the data as you expect? Even if it does, `setDestination` will run asynchronously, so you can't be sure it ran before `fetchDriverLocation` is called. I think you're going to need to rethink how this logic is implemented. Unfortuantely, I'm not sure how exactly, but doing some searching here on stackoverflow will probably help out finding the correct pattern. – Karl Galvez Oct 05 '21 at 01:56
  • Yes it returns the data I can log that data and also sets the data because I am using one of the set values somewhere else and it shows up. – incredible123 Oct 05 '21 at 02:00
  • Then I think it's the asynchronous nature of `setDestination` . The destination isn't set immediately, causing the error (odd it's undefined, when you set default as `''`). Can you show the code for `fetchTrackingData`? – Karl Galvez Oct 05 '21 at 02:07
  • It is happening because I am tapping into ```destination.coordinates``` but if I just console.log ```destination``` it doesn't show undefined – incredible123 Oct 05 '21 at 02:20

4 Answers4

1

What you're experiencing is a race condition.

When you call fetchTrackingData, it makes the HTTP request to your API, gets a response and then the last thing it does is saves destination to the state. But when you call setDestination, this is another asynchronous task that is kicked off, then you move directly to trying to access it from the state (which it may or may not be there, depending on how long it takes to set the state).

My recommendation would be to either not rely on state for this process (perhaps a variable will do? or even just passing along the result of your http request) or to lean more heavily on chaining these Promises and have the setting of the state be included in the Promise chain. However, I would favour the former suggestion

See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

and: Chain React setState callbacks

Brandon Mowat
  • 374
  • 1
  • 8
1

As another answer has stated, you are experiencing a race condition because setState in react is often asynchronous.

My suggestion would be to use two useEffects to accomplish this:

useEffect(() => {
  fetchTrackingData();
}, []);

useEffect(() => {
  console.log("Destination", destination.coordinates);
  fetchDriverLocation().finally(() => {
    setLoading(false);
  });
}, [destination]);

The above will wait until destination changes before moving on with fetching the driver location

smac89
  • 39,374
  • 15
  • 132
  • 179
-1

You can try with the async await methods and call the other APIs after the first one is done.

Example :

function App() {
  const [data, setData] = useState();
  const [data2, setData2] = useState();

  useEffect(() => {
    (async () => {
      const response = await fetch("someURL");
      const json = await response.json();
      setData(json);
      const responseList = await fetch("someURL" + json.data);
      const jsonData = await responseList.json();
      setData2(jsonData)
    })();
  }, []);


  return (
    <div>
        Hello
    </div>
  );
}

export default App;
Asif vora
  • 3,163
  • 3
  • 15
  • 31
  • using async/await is equivalent to what the OP has done. It won't solve the issue because setState is async – smac89 Oct 05 '21 at 15:48
-1

by using useEffect fetching data from firstURI and sending to secondURI

  const [firstDate, setFirstData] = useState();
  const [secondDate, setSecondData] = useState();

  useEffect(() => {
    (async () => {
      const firstResponse = await fetch("firstURI");
      const firstResponseData = await firstResponse.json();
      setFirstData(firstResponseData);
      
      const secondResponse = await fetch("secondURI" + firstResponseData.data);
      const secondResponseData = await secondResponse.json();
      setSecondData(secondResponseData)
    })();
  }, []);
Jimmy
  • 995
  • 9
  • 18
  • This doesn't give a solution because it is equivalent to what the OP had done. The problem is with `setState` not waiting for a promise to resolve – smac89 Oct 05 '21 at 15:51