YavarTechWorks
Published in

YavarTechWorks

React Recoil

Thumbnail credits: Nidhinkumar

If you don’t have time to read but want to know what’s there in this post. Find the quick read 👇

Quick read about Recoil

State management is one of the most important aspect of every app.The state dicates what users see, how the app looks, how the data is stored and so on.

React is likely the one that enjoys the most vibrant ecosystem including state management libraries. Though there are many state management libraries such as

  • Recoil
  • Redux
  • Jotai
  • Rematch
  • Zustand

On this Post

In this post, we are going to look at the Recoil state management library with the following topics

  1. Story behind the birth of Recoil
  2. Core Concepts
  3. Get Started with Recoil

So Let’s get started :)

1. Story behind the birth of Recoil (Motivation)

It’s best to use the React built-in state management rather than external state But React has certain limitation such as

  • Component state can only be shared by pushing it up to the common ancestor, but this might include a huge tree that then needs to re-render.
  • Context can only store a single value, not an indefinite set of values each with its own consumers.
  • Both of these make it difficult to code-split the top of the tree (where the state has to live) from the leaves of the tree (where the state is used).

Recoil defines a directed graph that is not just intrinsic to but also external to your React tree. State changes move from the graph’s roots (which is called as atoms), through pure functions (which is called as selectors), and into components. With this approach

  • We get a boilerplate-free API where shared state has the same simple get/set interface as React local state.
  • The state definition is incremental and distributed, making code-splitting possible. State can be replaced with derived data without modifying the components that use it.
  • We can treat navigation as a first-class concept, even encoding state transitions in links. It’s easy to persist the entire application state in a way that is backwards-compatible, so persisted states can survive application changes.

Recoil is designed to

  • Be minimal and Reactish.
  • Tame derived data and asynchronous queries through pure functions and efficient subscriptions.
  • Carry out cross-app observation and debugging without impairing code-splitting.

Facebook has successfully deployed Recoil in production for some of its internal tools.

2. Core Concepts

Recoil allows you to 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.

Let’s assume that we have an application like this

We see that the Navbar and the Profile component shares the same username state: nidhinkumar

And our component look like this

Component Tree

In the component tree land we could see that the Nav Component is far away from the Profile component.In order to have the same piece of state shared across all components, what you would normally do is prop drill state down from App to Home and Profile.

Prop drilling will be good for smaller application but what for a enterprise application which has more than 50,000 components it will be an headache.

So how does Recoil solves this issue? To answer in Recoil we will be using Atoms and Selectors

Atoms

Atoms are units of state. They’re updatable 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.

const fontSizeState = atom({
key: 'fontSizeState',
default: 14,
});

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 FontButton() {
const [fontSize, setFontSize] = useRecoilState(fontSizeState);
return (
<button onClick={() => setFontSize((size) => size + 1)} style={{fontSize}}>
Click to Enlarge
</button>
);
}

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 because 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 very efficient.

const fontSizeLabelState = selector({
key: 'fontSizeLabelState',
get: ({get}) => {
const fontSize = get(fontSizeState);
const unit = 'px';
return `${fontSize}${unit}`;
},
});

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.

In this fontSizeLabelState example, the selector has one dependency: the fontSizeState atom. Conceptually, the fontSizeLabelState selector behaves like a pure function that takes a fontSizeState as input and returns a formatted font size label as output.

3. Get Started with Recoil

Installation

The Recoil package lives in npm. To install the latest stable version, run the following command:

npm install recoil

RecoilRoot

Components that use recoil state need RecoilRoot to appear somewhere in the parent tree. A good place to put this is in your root component:

import '../styles/globals.css'
import type { AppProps } from 'next/app'
import { AuthProvider } from '../hooks/useAuth'
import { RecoilRoot } from 'recoil';
function MyApp({ Component, pageProps }: AppProps) {
return (
<RecoilRoot>
<AuthProvider>
<Component {...pageProps} />
</AuthProvider>
</RecoilRoot>
);
}
export default MyApp

Atom Creation

Now we will create an atom

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

Components that need to read from and write to an atom should use useRecoilState() as shown below:

function CharacterCounter() {
return (
<div>
<TextInput />
<CharacterCount />
</div>
);
}
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>
);
}

Selector Creation

A selector represents a piece of derived state. Derived state is a transformation of state. You can think of derived state as the output of passing state to a pure function that modifies the given state in some way:

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

We can use the useRecoilValue() hook to read the value of charCountState:

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

Congratulations!

In this post, we have seen the new state management for React Recoil.

Will catch up in a new post with more interesting crafts till then Happy Learning :)

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Nidhin kumar

Nidhin kumar

502 Followers

As a species, we have an inbuilt need to connect with others to communicate and share.