Recoil安装 #
安装 Recoil #
使用 npm #
bash
npm install recoil
使用 yarn #
bash
yarn add recoil
使用 pnpm #
bash
pnpm add recoil
版本要求 #
Recoil 对 React 版本有一定要求:
| Recoil 版本 | React 版本要求 |
|---|---|
| 0.7.x | React 16.8+ |
| 0.6.x | React 16.8+ |
| 0.5.x | React 16.8+ |
Recoil 依赖 React Hooks,因此需要 React 16.8 或更高版本。
基本配置 #
1. 添加 RecoilRoot #
在应用根组件包裹 RecoilRoot:
jsx
import React from 'react';
import { RecoilRoot } from 'recoil';
function App() {
return (
<RecoilRoot>
<YourApp />
</RecoilRoot>
);
}
export default App;
2. 完整示例 #
创建一个简单的计数器应用:
jsx
// App.jsx
import React from 'react';
import { RecoilRoot, atom, useRecoilState } from 'recoil';
const countState = atom({
key: 'countState',
default: 0,
});
function Counter() {
const [count, setCount] = useRecoilState(countState);
return (
<div style={{ textAlign: 'center', padding: '20px' }}>
<h2>计数器: {count}</h2>
<button onClick={() => setCount(c => c + 1)}>增加</button>
<button onClick={() => setCount(c => c - 1)}>减少</button>
<button onClick={() => setCount(0)}>重置</button>
</div>
);
}
function App() {
return (
<RecoilRoot>
<Counter />
</RecoilRoot>
);
}
export default App;
项目结构推荐 #
text
src/
├── atoms/ # Atom 定义
│ ├── index.js
│ ├── userAtoms.js
│ └── todoAtoms.js
├── selectors/ # Selector 定义
│ ├── index.js
│ └── userSelectors.js
├── components/ # React 组件
│ ├── Counter.jsx
│ └── UserList.jsx
├── hooks/ # 自定义 Hooks
│ └── useUser.js
└── App.jsx # 根组件
TypeScript 配置 #
安装 #
Recoil 自带 TypeScript 类型定义,无需额外安装:
bash
npm install recoil
npm install -D typescript
类型定义示例 #
tsx
import { atom, selector, useRecoilState, useRecoilValue } from 'recoil';
interface User {
id: number;
name: string;
email: string;
}
const userState = atom<User | null>({
key: 'userState',
default: null,
});
const userNameState = selector<string>({
key: 'userNameState',
get: ({ get }) => {
const user = get(userState);
return user?.name ?? 'Guest';
},
});
function UserProfile() {
const [user, setUser] = useRecoilState(userState);
const userName = useRecoilValue(userNameState);
return (
<div>
<p>User: {userName}</p>
<button onClick={() => setUser({ id: 1, name: 'John', email: 'john@example.com' })}>
Set User
</button>
</div>
);
}
与 Create React App 集成 #
bash
npx create-react-app my-app
cd my-app
npm install recoil
修改 src/index.js:
jsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import { RecoilRoot } from 'recoil';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<RecoilRoot>
<App />
</RecoilRoot>
</React.StrictMode>
);
与 Vite 集成 #
bash
npm create vite@latest my-app -- --template react
cd my-app
npm install recoil
修改 src/main.jsx:
jsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import { RecoilRoot } from 'recoil';
import App from './App';
import './index.css';
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<RecoilRoot>
<App />
</RecoilRoot>
</React.StrictMode>
);
与 Next.js 集成 #
bash
npx create-next-app@latest my-app
cd my-app
npm install recoil
创建 pages/_app.js:
jsx
import { RecoilRoot } from 'recoil';
export default function App({ Component, pageProps }) {
return (
<RecoilRoot>
<Component {...pageProps} />
</RecoilRoot>
);
}
RecoilRoot 配置选项 #
RecoilRoot 接受以下配置属性:
jsx
import { RecoilRoot } from 'recoil';
function App() {
return (
<RecoilRoot
initializeState={({ set }) => {
// 初始化状态
set(countState, 10);
}}
override={true}
>
<YourApp />
</RecoilRoot>
);
}
| 属性 | 类型 | 说明 |
|---|---|---|
initializeState |
function | 初始化状态的回调函数 |
override |
boolean | 是否覆盖嵌套的 RecoilRoot |
多个 RecoilRoot #
Recoil 支持多个 RecoilRoot 并存,实现状态隔离:
jsx
function App() {
return (
<div>
<RecoilRoot>
<Counter id="counter-1" />
</RecoilRoot>
<RecoilRoot>
<Counter id="counter-2" />
</RecoilRoot>
</div>
);
}
每个 RecoilRoot 拥有独立的状态存储,互不影响。
开发者工具 #
Recoil DevTools #
安装 Recoil DevTools 浏览器扩展:
使用 Snapshot Hook #
jsx
import { useRecoilSnapshot } from 'recoil';
function DebugObserver() {
const snapshot = useRecoilSnapshot();
React.useEffect(() => {
console.log('State changed:');
for (const node of snapshot.getNodes_UNSTABLE({ isModified: true })) {
console.log(node.key, snapshot.getLoadable(node));
}
}, [snapshot]);
return null;
}
function App() {
return (
<RecoilRoot>
<DebugObserver />
<YourApp />
</RecoilRoot>
);
}
常见问题 #
1. RecoilRoot 必须放在哪里? #
RecoilRoot 应该放在尽可能高的位置,通常在应用根组件:
jsx
// 正确
<RecoilRoot>
<App />
</RecoilRoot>
// 错误:子组件无法访问状态
<App>
<RecoilRoot>
<Child />
</RecoilRoot>
</App>
2. 可以在 RecoilRoot 外部使用 Recoil 吗? #
不可以。所有使用 Recoil 状态的组件必须在 RecoilRoot 内部。
3. 如何在组件外部访问状态? #
使用 useRecoilCallback:
jsx
import { useRecoilCallback } from 'recoil';
function MyComponent() {
const logState = useRecoilCallback(({ snapshot }) => () => {
const count = snapshot.getLoadable(countState).contents;
console.log('Current count:', count);
});
return <button onClick={logState}>Log State</button>;
}
验证安装 #
创建一个测试文件验证 Recoil 是否正确安装:
jsx
// test-recoil.jsx
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import { RecoilRoot, atom, useRecoilState } from 'recoil';
const testState = atom({
key: 'testState',
default: 'initial',
});
function TestComponent() {
const [value, setValue] = useRecoilState(testState);
return (
<div>
<span data-testid="value">{value}</span>
<button onClick={() => setValue('updated')}>Update</button>
</div>
);
}
test('Recoil works correctly', () => {
render(
<RecoilRoot>
<TestComponent />
</RecoilRoot>
);
expect(screen.getByTestId('value').textContent).toBe('initial');
fireEvent.click(screen.getByText('Update'));
expect(screen.getByTestId('value').textContent).toBe('updated');
});
总结 #
本章介绍了 Recoil 的安装和基本配置:
- 使用 npm/yarn/pnpm 安装 Recoil
- 在根组件添加 RecoilRoot
- 配置 TypeScript 支持
- 与不同项目脚手架集成
下一步,让我们学习 核心概念,深入理解 Recoil 的工作原理。
最后更新:2026-03-28