Why should I use Recoil?
The reason is that a detail page with very deep props transmission hierarchy and frequent state communication between components was recently refactored. The whole code is sorted out, it is difficult to maintain, consider when refactoring, do component subdivision, single out the data, and do a loose management of the data.
Comparing the Redux and Mobx I used before, it feels a bit heavy, because the project is refactored in the form of pure ts + Func hooks, and there are two drawbacks to applying these two more conventional state management tools:
- For the project code intrusion is relatively large, to write a lot of state management code (dispatch, action, reducer)
- Because they are external libraries, they don't have access to React's internal scheduler
The main thing is that these two libraries are a bit heavy for project use. There is no need to introduce a small npm dependency package for a not very complicated data management and communication. At first, Context was considered for processing, but multiple components subscribe to write multiple providers or have a root component provider to access data, which will lead to a lot of unnecessary redrawing and code amount. A colleague just mentioned Recoil (fb's own state management tool library for react), and after reading the information, I feel that it fits well with my project, so I tried it out and the effect is good.
A brief introduction to Recoil
Recoil is a state management solution proposed by FaceBook (personally feels like a lightweight state management tool tailored for react Func Comps).
We all know that React emphasizes immutable, and Recoil also emphasizes immutable. The benefit of immuteable is to enhance the overall application performance of components. It is not very clear about immutable, it is recommended to consult the relevant documents, which will not be elaborated here.
Recoil adopts the design pattern of decentralized management of atomic state.
Recoil proposes a new management state unit, Atom (Atomization), which can be updated and subscribed. When an Atom is updated, each component that subscribes to it will be updated and re-rendered with it. If multiple components use the same Atom , then these components will share their state.
It is not difficult to see from the above figure that its core concept is to atomically split data and manage data through a subscription-published model.
Recoil Basics
initialization
Components that use Recoil need to be wrapped with the RecoilRoot component
import React from 'react';
import { RecoilRoot } from 'recoil';
function App() {
return (
<RecoilRoot>
<CharacterCounter />
</RecoilRoot>
);
}
define state
We have mentioned the concept of Atom above. Atom is a new state, but unlike the traditional state, it can be subscribed by any component. When an Atom is updated, each subscribed component will use the new value to Re-render.
export const pageInfoState = atom({
key: 'pageInfoState',
default: {}
});
The key must be unique within the scope of RecoilRoot.
default defines the default value.
Subscription and update status
useRecoilState: A Hook similar to useState, which can get the value of atom and setter function.
useSetRecoilState: Only get the setter function. If only this function is used, the state change will not cause the component to re-render.
useRecoilValue: only get status.
useResetRecoilState: Reset the state.
import { nameState } from './store'
// useRecoilState
const NameInput = () => {
const [name, setName] = useRecoilState(nameState);
const onChange = (event) => {
setName(event.target.value);
};
return <>
<input type="text" value={name} onChange={onChange} />
<div>Name: {name}</div>
</>;
}
// useRecoilValue
const SomeOtherComponentWithName = () => {
const name = useRecoilValue(nameState);
return <div>{name}</div>;
}
// useSetRecoilState
const SomeOtherComponentThatSetsName = () => {
const setName = useSetRecoilState(nameState);
return <button onClick={() => setName('Jon Doe')}>Set Name</button>;
}
// useReSetRecoilState
const SomeOtherComponentThatSetsName = () => {
const ressetName = useSetRecoilState(nameState);
return <button onClick={ressetName}>Set Name</button>;
}
From the above, we can see that we use hooks to get and change the value, which is very friendly to react function components, and the code intrusion is very small.
Derived state
selector represents derived state, which allows us to build state that depends on other atoms (and also do some computational operations). It has a mandatory get function, somewhat similar to computed in Vue.
const lengthState = selector({
key: 'lengthState',
get: ({get}) => {
const text = get(nameState);
return text.length;
},
});
function NameLength() {
const length = useRecoilValue(charLengthState);
return <>Name Length: {length}</>;
}
Asynchronous state
Recoil provides a way to map state and derived state to React components via data flow graphs. The really powerful feature is that the functions in the graph can also be asynchronous. This allows us to easily use async functions in async React component render functions. With Recoil, you can seamlessly mix synchronous and asynchronous functionality in a selector's dataflow graph. Just return the Promise from the selector get callback, not the value itself.
For example, in the following example, if the username is stored in some database we need to query, then all we have to do is return a Promise or use an async function. If the userID changes, a new query is automatically re-executed. The result will be cached, so the query will only be executed once for each unique input (so make sure to keep the selector pure function, otherwise the cached result will be inconsistent with the latest value).
const userNameQuery = selector({
key: 'userName',
get: async ({get}) => {
const response = await myDBQuery({
userID: get(currentUserIDState),
});
return response.name;
},
});
function CurrentUserInfo() {
const userName = useRecoilValue(userNameQuery);
return <div>{userName}</div>;
}
Summarize
After using it, I feel that Recoil's distributed state management is a bit like the observable + computed mode. I haven't read the specific source code yet. After I find a time to read it, I will add another source code interpretation. In terms of usage, it completely caters to the usage of functional component Hooks, and does not provide the usage of Component.
The official product must be a high-quality product. The high performance promoted by the official document and the scheduling mechanism within React, including the previously promised concurrency mode, are still worth looking forward to (just listen to it). The main thing is to see the fit with your own project. You can use it if it suits you. The complexity of the project and the project has come up. It is better to choose a stable state management plan. Anyway, I plan to put Recoil in the project in the next stage. Spread the experience.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。