Hello,
I'm new to Recoil, and wonder if anyone could help me with some example on the following problem:
I want to create a state which can be used either offline or with slow or regular internet connection (it will be implemented in react native, but shouldn't really matter, looking for the concepts)
So I want to have a state which first use a default fixed init state, then start fetching both the async local state and from the backend API:
How can I achieve this in a clean, easy way?
In advance thank you! :D
I think you're looking for a combination of Atom Effects and a way of checking and hooking into network availability changes.
@hfalk - Please re-open the issue and let us know if you have further questions after checking out the Atom Effects docs that @BenjaBobs mentioned.
Thank you so much for the help! :) However, I'm struggling finding a sound way of implementing it.
The problem is: I need to refresh the backend data every now and then (independent of specific react components). And when the selector is finished with the refresh, it should update the local state(atom) and storage.
How can I do that? This is what I have so far:
const localFeatureTogglesState: RecoilState<FeatureToggles> = atom({
key: 'feature-toggles',
default: getLocalFeatureToggles(), // async get value from localStorage
effects_UNSTABLE: [asyncStorageEffect(FEATURE_TOGGLES_KEY)], // store newValue to localStorage, when atom updates
})
const refreshFeatureTogglesState = atom({
key: 'refresh-feature-toggles',
default: 0,
})
const remoteFeatureToggles: RecoilState<FeatureToggles> = selector({
key: 'remote-feature-toggles',
get: async ({ get }) => {
get(refreshFeatureTogglesState)
return await getRemoteFeatureToggles() // async get value from backend, should update `localFeatureTogglesState`, when receive new value
},
set: ({ set }, newValue) => {
if (newValue instanceof DefaultValue) {
set(refreshFeatureTogglesState, (v) => v + 1)
}
},
})
// Custom hook multiple components can use to get the latest data
export function useFeatureToggles(): [Loadable<FeatureToggles>, () => void] {
const localState = useRecoilValueLoadable(localFeatureTogglesState)
const remoteState = useRecoilValueLoadable(remoteFeatureToggles)
const refresh = useResetRecoilState(remoteFeatureTogglesState) // start refresh of remote data, need to save to local atom when finished
const state = // combined state with example values hasValue, hasValueAndLoading, loading, hasError, hasErrorAndLoading
return [state, refresh]
}
The effect could also manage remote storage and setup your subscription for occasional refresh. Or, if we support setting atoms to Promises (#237), it could be simply set to the new pending async value. Ideally, then, we could use something like useTransition() for working with previous state while new state is loading. However, there is still an issue with support for that in Recoil (#759).
So, in the meantime, some manual mechanism, as you describe above, is necessary to split state for the current local state and remote state if you need to seem them both simultaneously.
Most helpful comment
I think you're looking for a combination of Atom Effects and a way of checking and hooking into network availability changes.