Recoil核心概念 #
Recoil 的架构 #
Recoil 的架构设计非常简洁,核心概念只有三个:
text
┌─────────────────────────────────────────────────────────────┐
│ Recoil 架构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Atom │────▶│ Selector │────▶│ Component │ │
│ │ (状态单元) │ │ (派生状态) │ │ (React组件) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │ │ │ │
│ └───────────────────┴───────────────────┘ │
│ │ │
│ ┌────────▼────────┐ │
│ │ RecoilRoot │ │
│ │ (状态容器) │ │
│ └─────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
Atom(原子状态) #
什么是 Atom? #
Atom 是 Recoil 中最小的状态单元,类似于 React 的 useState,但它是全局的,可以被任何组件访问和修改。
Atom 的特点 #
| 特点 | 说明 |
|---|---|
| 独立性 | 每个 Atom 都是独立的状态单元 |
| 可读可写 | 可以读取和修改 Atom 的值 |
| 全局性 | 任何组件都可以访问 Atom |
| 响应式 | Atom 变化时,订阅它的组件会重渲染 |
创建 Atom #
jsx
import { atom } from 'recoil';
const countState = atom({
key: 'countState',
default: 0,
});
Atom 配置选项 #
jsx
const userState = atom({
key: 'userState',
default: null,
dangerouslyAllowMutability: false,
effects: [
({ onSet }) => {
onSet((newValue, oldValue) => {
console.log(`Value changed from ${oldValue} to ${newValue}`);
});
},
],
});
| 选项 | 类型 | 说明 |
|---|---|---|
key |
string | 唯一标识符,必须全局唯一 |
default |
any | 默认值或 Promise |
dangerouslyAllowMutability |
boolean | 是否允许直接修改对象 |
effects |
array | 副作用函数数组 |
使用 Atom #
jsx
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';
function Counter() {
const [count, setCount] = useRecoilState(countState);
return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}
function CountDisplay() {
const count = useRecoilValue(countState);
return <span>Count: {count}</span>;
}
function IncrementButton() {
const setCount = useSetRecoilState(countState);
return <button onClick={() => setCount(c => c + 1)}>+</button>;
}
Selector(选择器) #
什么是 Selector? #
Selector 是一个纯函数,它接受 Atom 或其他 Selector 作为输入,返回一个派生值。当依赖的状态变化时,Selector 会自动重新计算。
Selector 的特点 #
| 特点 | 说明 |
|---|---|
| 派生状态 | 基于其他状态计算得出 |
| 自动缓存 | 相同输入返回缓存结果 |
| 自动追踪依赖 | 自动检测依赖的状态 |
| 可异步 | 支持异步计算 |
创建只读 Selector #
jsx
import { selector } from 'recoil';
const doubleCountState = selector({
key: 'doubleCountState',
get: ({ get }) => {
const count = get(countState);
return count * 2;
},
});
创建可写 Selector #
jsx
const tempCelsiusState = atom({
key: 'tempCelsiusState',
default: 25,
});
const tempFahrenheitState = selector({
key: 'tempFahrenheitState',
get: ({ get }) => {
const celsius = get(tempCelsiusState);
return celsius * 9 / 5 + 32;
},
set: ({ set }, fahrenheit) => {
const celsius = (fahrenheit - 32) * 5 / 9;
set(tempCelsiusState, celsius);
},
});
使用 Selector #
jsx
function TemperatureConverter() {
const [celsius, setCelsius] = useRecoilState(tempCelsiusState);
const [fahrenheit, setFahrenheit] = useRecoilState(tempFahrenheitState);
return (
<div>
<input
value={celsius}
onChange={(e) => setCelsius(Number(e.target.value))}
/>
°C
<input
value={fahrenheit}
onChange={(e) => setFahrenheit(Number(e.target.value))}
/>
°F
</div>
);
}
RecoilRoot(状态容器) #
什么是 RecoilRoot? #
RecoilRoot 是 Recoil 的状态容器组件,它创建了一个状态存储上下文,所有使用 Recoil 的组件必须在其内部。
RecoilRoot 的作用 #
text
┌─────────────────────────────────────────┐
│ RecoilRoot │
│ ┌───────────────────────────────────┐ │
│ │ 状态存储 (Store) │ │
│ │ ┌─────────┐ ┌─────────┐ │ │
│ │ │ Atom A │ │ Atom B │ │ │
│ │ └─────────┘ └─────────┘ │ │
│ │ ┌─────────┐ ┌─────────┐ │ │
│ │ │Selector │ │Selector │ │ │
│ │ │ C │ │ D │ │ │
│ │ └─────────┘ └─────────┘ │ │
│ └───────────────────────────────────┘ │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │Component│ │Component│ │Component│ │
│ │ A │ │ B │ │ C │ │
│ └─────────┘ └─────────┘ └─────────┘ │
└─────────────────────────────────────────┘
RecoilRoot 配置 #
jsx
import { RecoilRoot } from 'recoil';
function App() {
return (
<RecoilRoot
initializeState={({ set }) => {
set(countState, 10);
set(userState, { name: 'John' });
}}
>
<YourApp />
</RecoilRoot>
);
}
状态流 #
数据流向 #
Recoil 采用单向数据流:
text
┌──────────────┐
│ Atom │
│ (状态源) │
└──────┬───────┘
│
▼
┌──────────────┐
│ Selector │
│ (派生状态) │
└──────┬───────┘
│
▼
┌──────────────┐
│ Component │
│ (消费者) │
└──────┬───────┘
│
│ set()
│
▼
┌──────────────┐
│ Atom │
│ (状态更新) │
└──────────────┘
状态更新流程 #
jsx
const countState = atom({ key: 'count', default: 0 });
function Counter() {
const [count, setCount] = useRecoilState(countState);
const increment = () => {
setCount(count + 1);
};
return <button onClick={increment}>{count}</button>;
}
执行流程:
- 用户点击按钮
- 调用
setCount(count + 1) - Recoil 更新 Atom 的值
- 通知所有订阅该 Atom 的组件
- 组件重渲染
依赖图 #
Recoil 自动构建状态依赖图:
jsx
const firstNameState = atom({
key: 'firstName',
default: 'John',
});
const lastNameState = atom({
key: 'lastName',
default: 'Doe',
});
const fullNameState = selector({
key: 'fullName',
get: ({ get }) => {
const first = get(firstNameState);
const last = get(lastNameState);
return `${first} ${last}`;
},
});
依赖关系:
text
firstNameState ──┐
├──▶ fullNameState
lastNameState ───┘
当 firstNameState 或 lastNameState 变化时,fullNameState 会自动重新计算。
细粒度更新 #
Recoil 实现了真正的细粒度更新:
jsx
const nameState = atom({
key: 'name',
default: { firstName: 'John', lastName: 'Doe' },
});
function FirstName() {
const name = useRecoilValue(nameState);
return <span>{name.firstName}</span>;
}
function LastName() {
const name = useRecoilValue(nameState);
return <span>{name.lastName}</span>;
}
注意:Atom 是整体更新的,如果需要细粒度更新,应该拆分为多个 Atom:
jsx
const firstNameState = atom({ key: 'firstName', default: 'John' });
const lastNameState = atom({ key: 'lastName', default: 'Doe' });
异步状态 #
Recoil 原生支持异步状态:
jsx
const userQuery = selector({
key: 'userQuery',
get: async ({ get }) => {
const userId = get(userIdState);
const response = await fetch(`/api/users/${userId}`);
return response.json();
},
});
function UserProfile() {
const user = useRecoilValue(userQuery);
return <div>{user.name}</div>;
}
Loadable 状态 #
异步状态有三种状态:
jsx
const userLoadable = useRecoilValueLoadable(userQuery);
switch (userLoadable.state) {
case 'hasValue':
return <div>{userLoadable.contents.name}</div>;
case 'loading':
return <div>Loading...</div>;
case 'hasError':
return <div>Error: {userLoadable.contents.message}</div>;
}
总结 #
Recoil 的核心概念非常简洁:
| 概念 | 作用 |
|---|---|
| Atom | 最小状态单元,可读可写 |
| Selector | 派生状态,自动追踪依赖 |
| RecoilRoot | 状态容器,提供上下文 |
这些概念组合起来,可以构建复杂的状态管理系统。
下一步,让我们学习 Atom基础,深入了解 Atom 的使用方法。
最后更新:2026-03-28