An Intro to Recoil. The State Management Library for React
Relatively new on the scene, Recoil is a state management system made to work and think like React. This article breaks down what it is, how it works, and how to use it.
Table of Contents
What is Recoil?
Recoil is a minimal experimental state management library for React by Facebook. If you have used Redux or React Context with Providers, the concept is very similar. RecoilRoot is added somewhere in the parent tree. This then provides context to all of the child components within.
Why Recoil instead of Context or Redux?
Existing state management systems like Context work well for their particular use cases. Redux can be very helpful when scaling a large application. However both Redux and Context have certain limits when it comes to flexibility and performance. Due to the way that they require code to be written, it can become bug prone when scaled. You might find this helpful if interested in Context: Quick and Easy React Provider and Context with Hooks Template Recoil provides the following benefits:
Flexible Shared State
Components across the React tree are able to be synced with less of a performance hit on the browser.
Derived Data and Queries
A simple and efficient way to implement calculations on changed state. Each packaged into its own function to allow faster development. This provides a better developer experience and helps reduce potential bugs.
App-Wide State Observation
Much like Redux, Recoil supports time travel debugging, undo support and logging. Being able to fully observe the state and what is happening was not possible with Context, and is fairly plug and play.
How To Use Recoil
There are a few essential pieces that Recoil needs to function. These are:
- RecoilRoot
- Atom
- Selector
- useRecoilState
- useRecoilValue
There are other hooks that can be used, but these should get you moving.
What is RecoilRoot?
RecoilRoot can be thought of as the ‘provider’ of the app context or state. A simple example of using the RecoilRoot looks like this:
import { RecoilRoot } from "recoil"; function AppRoot() { return (
<RecoilRoot> <ComponentThatUsesRecoil /> </RecoilRoot>
); }
Multiple Recoil roots can be used together within an app, with the newest – or innermost root taking completely masking any of the outer roots. The state that has been passed down from the Recoil Roots can then be accessed by Atoms.
What is an Atom?
If you have used the useState hook before, Atoms are very similar. Atoms are used with useRecoilState to get or set a single piece of state from its Recoil Root context. The Atom is the name and the value of the state – like a key within a database. They are a changeable, subscribable piece of state. When an Atom is updated, any components that are subscribed to that state are re-rendered with the new value. Each Atom must be completely unique, so requires its own unique ID known as a key. An example of how an Atom is used:
import { atom, useRecoilState } from 'recoil'; const counter = atom({ key: 'myCounter', default: 0, }); function Counter() { const [count, setCount] = useRecoilState(counter); const increment = () => setCount(count + 1); return ( < div >
Count: {count} <button onclick="{increment}">Increment</button>
</div > ); }
The great part about Atoms is that they can be declared in a module outside of a component, much like React Hooks, and then imported into a component when needed. This makes sharing state far easier than before.
What is a Selector?
Selectors are pure functions that take Atoms as an input. Much like Atoms they need a unique key to identify them. A Selector is used to compute calculations that rely on the state. When an Atom state updates, the selector listens to this – reruns its calculation – and returns the changed value. Components are able to subscribe to Selectors in the same way they can subscribe to Atoms. An example of how to use Selectors:
import { atom, selector, useRecoilState } from "recoil"; const fahrenheit = atom({ key: "fahrenheit", default: 32 }); const celcius = selector({ key: "celcius", get: ({ get }) => ((get(fahrenheit) - 32) * 5) / 9, set: ({ set }, newValue) => set(fahrenheit, (newValue * 9) / 5 + 32) }); function TempCelcius() { const [tempF, setTempF] = useRecoilState(fahrenheit); const [tempC, setTempC] = useRecoilState(celcius); const addTenCelcius = () => setTempC(tempC + 1); const addTenFahrenheit = () => setTempF(tempF + 1); return (
<div> Temp (Celcius): {tempC} Temp (Fahrenheit): {tempF} <button onclick="{addCelcius}">Add 1 Celcius</button> <button onclick="{addFahrenheit}">Add 1 Fahrenheit</button> </div>
)
What is useRecoilState?
As you may have seen in the above code examples, useRecoilState is almost identical to the useState React hook. It returns the value, and the setter for a piece of state.
const [state, setState] = useRecoilState(atomName);
Use state within a component as the value, and use the setState function to set the state of the Atom. Simple, concise and easy to set up.
What is useRecoilValue?
useRecoilValue gets the current state of an Atom and allows a component to subscribe to that state. When the Atom updates, the useRecoilValue gets that state and passes it through.
const state = useRecoilValue(atomName);
This allows components that do not require the ability to set an Atoms state to use the state with no added overhead.
Overview
Recoil sounds like it is set to be incredibly helpful in app development and looks easy to implement. The ability to easily set and get state, as well as share it across an application quickly looks very appealing. I will personally be holding back to see how it fairs in production, and which way the Open Source community takes it. For more information on usage, and the other hooks – take a look at https://recoiljs.org/