Recoil is a Facebook status management library released at the React Europe 2020 Conference. I think many people are interested in Recoil, so I spent a few days putting together some materials and sharing a primer. The following is mainly toWhy Recoil -> When Recoil -> How RecoilIn order to introduce Recoil.

1.Why Recoil

Why does it appear? The source of the problem can be traced back to the React framework itself, because React specifies that the flow of data is passed and updated from outer components to inner components. Component state can only be shared with its ancestor components, which may cause a lot of redrawing overhead in the component tree and inconvenient communication between components.

Context can solve this problem, but the problem with Context is:

Context can only store a single value, Not an indefinite set of values each with its own consumers.

This makes it very difficult to split the code between components at the top of the component tree (state producers) and components at the bottom of the component tree (state consumers).

The above is the explanation given in the official document. When I first read it, I read ๐Ÿ˜ต. When you look at it, you realize what it really means:

  1. First of all to understandContextHow it works: Because wheneverProviderWhen the value ofProviderAll of posterityConsumersWill be re-rendered.
  2. When there are multipleConsumerWhen, in order to avoid unnecessary updates, will not put allConsumersAll the states you use are crammed into the same oneProvider.
  3. So there are more than oneProvider-ConsumerIn order to manage their own state, each other.
  4. But this presents another problem: code coupling makes it difficult to split. (End sahwa ๐ŸŒธ)

To get back to the point, these issues were the driving force behind Recoil’s creation, as well as the need to manipulate data streams more subtly to achieve high performance. Recoil plans to address these issues differently from Redux and Mobx:

  • Flexible Shared State: Flexibly share state anywhere in the React Tree while maintaining high performance
  • Derived data and queries: Efficiently and reliably perform calculations based on the changing state
  • App-wide State Observation: Time travel debugging, support undo, log persistence

Recoil gave birth to ๐Ÿฃ๐Ÿฃ๐Ÿฃ๐Ÿฃ๐Ÿฃ๐Ÿฃ๐Ÿฃ

2.When Recoil

When do we use it?

Comparing the existing state libraries redux and Mobx, the main differences are:

State management library Redux Mobx Recoil
process Standard/complex Free/Simple Standard/simple
Rely on redux/react-redux/redux-saga mobx/mobx-react recoil
support Class/function components Class/function components Function component
Learning costs high low low
thought functional responsive hook
version A formal A formal test

Therefore, based on the above analysis, we can consider using Recoil when meeting the needs of React project && using Hook && small projects.

3.How Recoil

How does Recoil achieve state management?

Let’s look at how Recoil achieves Flexible shared State, Derived data and queries ๐Ÿ˜Š.

Shared state

One application is based on a scenario that updates a node in the List and then updates the corresponding node in the Canvas

Recoil took the approach of creating another orthogonal Tree on the React Tree, extracting the state of each node. Each component has a separate slice of state, and the corresponding component updates when data is updated. Recoil calls each slice of data an Atom, which is a subscriptable variable unit of state. As shown in the figure:

Derived Data

There is a scenario where a List based derived state such as totalNum, totalCompletedNum is computed from a List.

This smells a bit like @computed in Mobx ๐Ÿคจ, and the idea behind Derived Data is to take multiple Atoms, compute them, and return a new state. So an API like Selector was designed in Recoil to take multiple Atom and evaluate it. And the selector design is a little bit like a Proxy, you have get on the property to read it, you have set on the property to set it, you have get on the inside of the function, you have set on the state.

So how do we use it?

Go ahead and try out a demo, but it’s good to know a few important concepts before writing a demo:

  • Similar to theProvideruseRecoilYou need to wrap a layer around the root node<RecoilRoot/>
  • AtomRepresents the state,SelectorRepresents derived state
  • Common hook functions areuseRecoilValue,useSetRecoilState,useRecoilState

Here are a few lines of useRecoilState source code, I believe you will know the purpose of these three hooks:

function useRecoilState<T>(
  recoilState: RecoilState<T>,
): [T, SetterOrUpdater<T>] {
  if (__DEV__) {
    // $FlowFixMe[escaped-generic]
    validateRecoilValue(recoilState, 'useRecoilState');
  }
  return [useRecoilValue(recoilState), useSetRecoilState(recoilState)];
}
Copy the code

Here is an official simple demo: see demo

//App.js
import React from 'react';
import { RecoilRoot } from 'recoil';
import CharacterCounter from './pages/charCounter'

export default function App() {
  return (
    <RecoilRoot>
      <CharacterCounter />
    </RecoilRoot>
  );
}

Copy the code
//charCounter.js import { useRecoilState, useRecoilValue } from 'recoil' import { textState, charCountState } from '.. /store/charCounterStore' export default function CharacterCounter() { return ( <div> <TextInput /> <CharacterCount /> </div> ); } function TextInput() { const [text, setText] = useRecoilState(textState); const onChange = (e) => setText(e.target.value); Return (<div> <input type="text" value={text} onChange={onChange} /> Input text: {text} </div>); } function CharacterCount() { const count = useRecoilValue(charCountState); Return <> Input length: {count}</>; }Copy the code
//charCounterStore.js import { atom, selector } from 'recoil'; export const textState = atom({ key: 'textState', default: '' }) export const charCountState = selector({ key: 'charCountState', get: ({get})=>{ const text = get(textState) return text.length; }})Copy the code

UseRecoilState is a lot like useState, except that useRecoilState receives atom or selector initialization arguments. When a component needs a shared state (Atom), it simply imports the shared state through the Recoil hook. When the Atom changes, all other components that subscribe to the atom will synchronize the data ๐Ÿ‘.


Finally, a few points not mentioned in the article:

  • Recoil can treat navigation as a first-class citizen and can even code the state in links.
  • Recoil has the potential to be compatible with concurrency and other React features.
  • Recoil can use React’s internal scheduling mechanism, which Redux and Mobx don’t support.
  • Happy Labor Day ๐Ÿฅณ๐Ÿฅณ๐Ÿฅณ