2

I'm trying to understand React Recoil and when an updated atom's value is available, or how to make the new value propagate vertically and horizontally across the app.

For example if I have an atom called userState and I update one of its properties like avatar_url, the value is not the new value if I console it right after the setUser.

const [user, setUser] = useRecoilState(userState);

setUser({ avatar_url: imageURL, ...appUser});

console.log(imageURL); // is the actual new URL
console.log(user.avatar_url); // should be new URL but isn't
Kirk Ross
  • 6,413
  • 13
  • 61
  • 104
  • 2
    Does this answer your question? [Why calling react setState method doesn't mutate the state immediately?](https://stackoverflow.com/questions/30782948/why-calling-react-setstate-method-doesnt-mutate-the-state-immediately) – CertainPerformance Dec 02 '20 at 02:28

1 Answers1

6

It's not related to Recoil but to React, the updated value is available on the next render as setState (which Recoil is built on) is async.

setState() does not immediately mutate this.state but creates a pending state transition. Accessing this.state after calling this method can potentially return the existing value. There is no guarantee of synchronous operation of calls to setState and calls may be batched for performance gains.

You should use useEffect to simulate this behavior:

const [user, setUser] = useRecoilState(userState);

setUser({ avatar_url: imageURL, ...appUser});

useEffect(() => {
  console.log(user.avatar_url);
}, [user]);
Dennis Vash
  • 50,196
  • 9
  • 100
  • 118
  • many thanks for the enlightenment. In this case, it's all inside a useCallback so useEffect can't be used. I think I need to rethink this on a broader level and get deeper into Recoil, using subscriptions and methods talked about here: https://recoiljs.org/docs/guides/asynchronous-state-sync – Kirk Ross Oct 25 '20 at 06:22
  • @KirkRoss Using subscriptions (which is basically just a useEffect, since Recoil doesn't know about subscriptions) won't change the update behavior of React. This is just how React fundamentally works. All state updates are asynchronous and there isn't a guaranteed "timeframe" in which the value gets propagated. If you really want to dig in into the how and why, you can check out this article: https://indepth.dev/inside-fiber-in-depth-overview-of-the-new-reconciliation-algorithm-in-react/ – Johannes Klauß Oct 25 '20 at 19:07
  • If it is inside a useCallback you should just be able to add `user` to your dependency array. When `user` is updated with the new value, your function in useCallback will be updated with that value as well – HaveSpacesuit Dec 22 '20 at 16:20
  • 1
    When using Recoil, my experience is that there is no guarantee the value will have updated by next render. – Chris Haines Jun 18 '21 at 11:14
  • 1
    See for example this issue: https://github.com/facebookexperimental/Recoil/issues/1076 – Chris Haines Jun 18 '21 at 11:22