0

I'm trying to set the value of a hook inside a Promise function inside a useEffect() and being able to store the returned promise value in the fruit hook so I can access it in the return function of MyComponent()

This is what I tried so far:

const MyComponent = () => {
  const [fruit, setFruit] = useState('')

  useEffect(() => {
    // my promise function that returns a string (a random fruit)
    promiseFunction()
      .then(value => setFruit(value))
  }, [])

  return <div>fruit ? fruit : Loading...</div>
}

I have tried many approachs so far but none of them worked.

useEffect(() => {
  promiseFunction()
    .then(value => setFruit(() => value))
}, [])
useEffect(() => {
  promiseFunction()
    .then(value => setFruit((value) => { fruit = value }))
}, [])

After all that, the returned value of the hook is still empty.

There are no errors messages or anything, I tried debugging using another useEffect and it still returns an in the console.

How can I get the returned value of the promise function and store it in the fruit variable?

  • Did you confirm (with `console.log` messages or debugging) that the promise actually fulfills with a non-empty `value`? – Bergi May 20 '21 at 12:44
  • `
    fruit ? fruit : Loading...
    ` needs to be `
    {fruit ? fruit : 'Loading...'}
    ` but otherwise the first snippet should work fine. Don't forget to add a `.catch()` error handler to your promise.
    – Bergi May 20 '21 at 12:45
  • @Bergi Yes, it does return a value – Michael Burns May 20 '21 at 12:53
  • Then there should be no issue. Please provide a [mcve] – Bergi May 20 '21 at 12:55

1 Answers1

3

The first code example looks perfect to me. My only concern is that the value is not being correctly returned from the function itself.

Have you tried to log the return from the promiseFunction? Another way to write this code would be to use a function that you can call inside the useEffect itself, like this:

useEffect(() => {
  async function loadFruitData() {
    const promiseFunctionReturn = await promiseFunction()
    
    console.log(promiseFunctionReturn)

    setFruit(promiseFunctionReturn)
  }
  
  //Call the function
  loadFruitData();
}, [])

This should give you a better way to see whats happening, and I also find it more readable.

But remember, if you're trying to console.log() the data right after the setFruit, it wouldn't show you the updated state, it happens because React has a queue that make the updates caused by the useState, that make it looks like an asynchronous update.

Dharman
  • 30,962
  • 25
  • 85
  • 135
josepholiveira
  • 663
  • 6
  • 10
  • I can't really edit the original promiseFunction as it is from a npm package. My code is just an example of what I'm trying to do – Michael Burns May 20 '21 at 12:52
  • Ok, my first example actually works.. I just did the console.log() after the setState and I actually didn't know that React has a queue for updates. Where can I learn more about react queues? Many thanks. – Michael Burns May 20 '21 at 12:56
  • If I'm not mistaken, when using Class Components, Dan Abramov explained about these updates in a Issue in github, you can check it out here: https://github.com/facebook/react/issues/11527#issuecomment-360199710 When using functional components, with useState, the useState call the component to be rendered again, making the values update, that's why you can't immediately log it out. I can't find a doc for it, but I think you can read about it here: https://medium.com/swlh/javascript-closures-and-react-4c0e3f705a6c – josepholiveira May 20 '21 at 13:05
  • I found it in the oficcial docs: https://reactjs.org/docs/hooks-faq.html#what-can-i-do-if-my-effect-dependencies-change-too-often It has a shallow explanation about it, but should help. But basically its a closure that makes the component re-render and update the values, and in the docs it shows how to avoid unwanted effects when updating the state multiple times! – josepholiveira May 20 '21 at 13:12