Recoil

Stefano Di Cecco
3 min readMar 11, 2021

Recoil is an experimental set of utilities for state management with React. Recoil lets you create a data-flow graph that flows from atoms (shared state) through selectors (pure functions) and down into your React components. Atoms are units of state that components can subscribe to. Selectors transform this state either synchronously or asynchronously.

  • Atoms

Atoms are units of state. They’re updateable and subscribable: when an atom is updated, each subscribed component is re-rendered with the new value. They can be created at runtime, too. Atoms can be used in place of React local component state. If the same atom is used from multiple components, all those components share their state.

Atoms are created using the atom function:

const textState = atom({
key: "textState", // unique ID (with respect to other atoms/selectors)
default: "", // default value (aka initial value)
});

Atoms need a unique key, which is used for debugging, persistence, and for certain advanced APIs that let you see a map of all atoms. It is an error for two atoms to have the same key, so make sure they’re globally unique. Like React component state, they also have a default value.

To read and write an atom from a component, we use a hook called useRecoilState. It’s just like React’s useState, but now the state can be shared between components:

function TextInput() {
const [text, setText] = useRecoilState(textState);
const onChange = (event) => {
setText(event.target.value);
};
return (
<div>
<input type="text" value={text} onChange={onChange} />
<br />
Echo: {text}
</div>
);
}
  • Selectors

A selector is a pure function that accepts atoms or other selectors as input. When these upstream atoms or selectors are updated, the selector function will be re-evaluated. Components can subscribe to selectors just like atoms, and will then be re-rendered when the selectors change.

Selectors are used to calculate derived data that is based on state. This lets us avoid redundant state, usually obviating the need for reducers to keep state in sync and valid. Instead, a minimal set of state is stored in atoms, while everything else is efficiently computed as a function of that minimal state. Since selectors keep track of what components need them and what state they depend on, they make this functional approach more efficient.

From the point of view of components, selectors and atoms have the same interface and can therefore be substituted for one another.

Selectors are defined using the selector function:

const charCountState = selector({
key: "charCountState", // unique ID (with respect to other atoms/selectors)
get: ({ get }) => {
const text = get(textState);
return text.length;
},
});

The get property is the function that is to be computed. It can access the value of atoms and other selectors using the get argument passed to it. Whenever it accesses another atom or selector, a dependency relationship is created such that updating the other atom or selector will cause this one to be recomputed.

Selectors can be read using useRecoilValue(), which takes an atom or selector as an argument and returns the corresponding value. We don’t use the useRecoilState():

function CharacterCount() {
const count = useRecoilValue(charCountState);
return <>Character Count: {count}</>;
}

Writing inside the field now does two things: count the characters while also updating the label to reflect the current field value.

Yaaay! 🎉

I hope you learned some new stuff !!!

Leave a comment if you want or ask some questions and if you like follow me!

Cheers!

Reference

--

--

Stefano Di Cecco

Self-motivated IT professional with great knowledge and proficiency in JavaScript, TypeScript. Expertise in frameworks like React.js, Angular.