I'm trying to store a user object inside an atom and have it be cached inside localStorage
each time it changes because the app might crash and I do not want the user to have to sign in every time:
localStorage.setItem('user', JSON.stringify(user))
Previously when I used useContext
this was achieved through a useEffect
in the parent component (App.js) that monitored the user
object for changes. It's no longer possible for me to do this after migrating from useContext
to Recoil
due to my NextJS project structure (RecoilRoot
wraps around the children component, so the parent App.js
itself does not have access to useRecoil
methods). And so, I'm wondering if there's a way to implement this kind of listener or callback using a built-in Recoil method
Desired process:
const [user, setUser] = useRecoilState(userAtom)
setUser({...})
localStorage.setItem('user', JSON.stringify(user))
Solution: There's a built-in effects
hook in the atom()
constructor
Docs: https://recoiljs.org/docs/guides/atom-effects/ (Refer to 'Logging Example')
export const userAtom = atom({
key: 'user',
default: null,
effects: [
({onSet}) => {
onSet(data => {
localStorage.setItem('user', JSON.stringify(data))
console.log("Updated User Data (state.tsx): ", data)
})
}
]
})
You can use the useEffect
hook, which lets you do something extra when your atom state changes. You can get the current value of your atom state with the useRecoilValue
hook, and then pass it as a dependency to useEffect
. Inside useEffect
, you can save the user
object in localStorage
so you don't lose it. For example:
import { useRecoilValue } from "recoil";
const userAtom = atom({
key: "userAtom",
default: null,
});
const userValue = useRecoilValue(userAtom);
useEffect(() => {
localStorage.setItem("user", JSON.stringify(userValue));
}, [userValue]);