Recoil: onSet() handler in effect not triggered when atom initialized via RecoilRoot initializeState or snapshot
RecoilRoot using initializeState:
<RecoilRoot
initializeState={({ set }) => set(domainState, props.savedDomainState)}
>
<AppRoot root={props.root} />
</RecoilRoot>
The Atom using an effect:
const domainState = atom({
key: "domainState",
default: null,
effects_UNSTABLE: [syncDomainStorage],
});
The function: syncDomainStorage is only triggered on initial render when I use initializeState
, only if I remove initializeState
the side-effect function is called when the atom is updated.
Any updates to domainState
atom should be triggering the effect, which is not the behavior observed when used along with RecoilRoot initializeState
About this issue
- Original URL
- State: open
- Created 4 years ago
- Reactions: 8
- Comments: 19 (6 by maintainers)
Hey! Thanks for reply @drarmstr .
I’m using cookies from request header to set Atoms state on initial Server-side render. And I want
effects_UNSTABLE onSet()
to mutate cookie client-side when state changes.My problem is probably framework-specific since nextjs framework gets ServerSide parameters and passes them to components like this
<App {...serversideprops}></App>
soinitializeState
is very helpful. And I couldn’t figure out how to pass current cookie header from request to atomeffects_UNSTABLE setSelf
😦Would’ve been perfect combo to have peristent state in cookies if only
onSet()
ineffects_UNSTABLE
could be used withinitialState
. I’m just using regularuseEffect
to set a cookie after changing atom state for now.Added example here.
_app.js
- here I pass cookies to initializeState on initial server-side render. (BreakssetSelf()
)index.js
- example of current behaviour.Should be fixed with #1511 and tested with #1519 for 0.6 release.
Note you’ll also be able to initialize atoms using props with the upcoming
recoil-sync
library and effects instead ofinitializeState
. (https://github.com/facebookexperimental/Recoil/pull/1462/files)Yep, provided workarounds won’t work for example with SSR, where I want to initialize with
initializeState
prop on inital SSR render, but keep theeffects_UNSTABLE
onSet()
callback functionality.Is this issue fixed?
I’ve got an atomEffect which tracks the “history” of an atom by pushing into an array each
onSet
but it doesn’t update when changed within the RecoilRoot initializeState(I’m using Recoil 0.7.5)
Bump! I’m in the same boat as @Noo8lord - I have a NextJS SSR app in production which relies on session tokens to understand who the user is, fetch data on the server, and initialize recoil state in recoil root. Was hoping that I could initialize atoms from the server as I’ve been doing, and then use the
onSet()
atom effect to manage subsequent recoil state persistence and side effects, but it doesn’t seem to be possible.As mentioned somewhere above, the workaround of enabling effects by dropping
initializeState
in favor of asynchronoussetSelf
effects for each atom isn’t useful in my case because it seems to negate the utility of SSR, and because I can’t give the atom effects the context they need to fetch the right data on the server.Appreciate any help / follow up and happy to provide more info.
@drarmstr I’ve added a PR https://github.com/facebookexperimental/Recoil/pull/828 for an update docs with the asynchronous / promise examples we discussed. I would have liked that when looking through the docs, so maybe other would as well.
Let me know if there’s something badly explained.
Note that Atom Effect functions are themselves not
async
and should not return aPromise
. You can schedule async calls tosetSelf()
in them, but that will only set the atom value asynchronously after initial render, not initialize the atom state for initial render (which would use the atom’s default value). If you need to get the initial state asynchronously you could synchronously callsetSelf()
with an asyncPromise
. This will cause the atom to be initialized in a pending state that will leverage Suspense for the initial render. The approach you want is up to you, but be aware of the differences.