Skip to main content

ReactJS: State Persistence Using React Recoil

· 4 min read
Joie Llantero

Recoil is an open-source experimental state management library by Facebook. It's one of the many libraries that makes managing states easier like persisting the theme state (light/dark mode) of your website. Other examples of such libraries are Xstate, Redux, Zustand, and Jotai.

Getting Started

In your project, install Recoil using the npm command below.

npm install recoil

or if you're using yarn.

yarn add recoil

You can view more installation guides in the documentation here.

Next, we need to add Recoil to our index.js so that we can use it everywhere in our project.

...
import { RecoilRoot } from "recoil";

ReactDOM.render(
...
<RecoilRoot>
<AppRoutes />
</RecoilRoot>
...
document.getElementById('root')
);

Creating an atom

Atoms contain the source of truth for our application state and below is an example of creating an atom.

export const darkModeState = atom({
key: 'darkMode',
default: false,
});

For use cases like this, I like to put my atoms inside a globalState.js file inside the shared folder of my project. This is because many components will share this atom. Moreover, inside the atom that I made is a unique key and a default value. An atom key is a serializable value that labels the atom and it's useful especially when we want to persist our state. On the other hand, the default value is the default state of the atom.

Using the atom in your component is almost similar to useState hooks.

const [isDarkModeEnabled, setIsDarkModeEnabled] = useRecoilState(darkModeState);

Instead of useState, we use useRecoilState and instead of passing the default state, e.g., false, we pass in our atom, i.e., darkModeState.

When we don't need to change the state of the atom and only need access to its value, we can simply do it like the code snippet below.

const isDarkModeEnabled = useRecoilValue(darkModeState);

Saving the state to local storage

There are use cases when we want to keep states like saving the preferred theme to the website visitor's browser local storage. This helps returning visitors to keep their preferred settings that they set on their previous visit.

Below is an example of using Recoil to persist the theme of a website.

const localPersist = ({onSet, setSelf, node}) => {
const storedData = localStorage.getItem(node.key)
if (storedData != null){
setSelf(JSON.parse(storedData))
}
onSet((newData, __, isReset) => {
isReset
? localStorage.removeItem(node.key)
: localStorage.setItem(node.key, JSON.stringify(newData));
})
}

export const darkModeState = atom({
key: 'darkMode',
default: false,
effects: [localPersist]
});

Notice the effects parameter that I added to my atom. That parameter is called atom effects and it's an API for managing side-effects and synchronizing or initializing Recoil atoms. It's typically used in state persistence, synchronization, managing history, etc. As seen above, I passed the function that handles saving, removing, and getting the state from the browser's local storage

Furthermore, the localPersist function can be called by any atom. In other words, if you need a state to persist, you can just call the function to persist your state. Besides boolean values, the function also works for other data types like strings, objects, and arrays.

export const myStringState = atom({
key: 'myString',
default: '',
effects: [localPersist]
});

export const myListState = atom({
key: 'myList',
default: [],
effects: [localPersist]
});

Inside the localPersist function we have the onSet function which gets called when our atom changes. To get the state from our local storage, we use the setSelf function. Moreover, the isReset function is used when the useResetRecoilState is called which removes the state from the browser's local storage.

Now that we've finished setting up the globalState.js, we now have states that are accessible to multiple components which also persists. You can check if it works by going to inspect element > Application tab > Storage > Local Storage > http://your-website-url.

Final Thoughts

Recoil is easy to implement and as seen earlier, it's similar to how we use useState. There are many new state management libraries currently existing and maybe more will be released. Jotai is an example of a state management library that is similar to Recoil–they are both atomic. Other types of libraries are flux (Redux, Zustand) and proxy (Mobs, Valtio, Overmind). At the end of the day, choosing the right library for your project depends on many variables like package size, use case, and more.

tutorial demo

Click here to view a sample implementation of what we've discussed.