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 的安装和基本配置:

  1. 使用 npm/yarn/pnpm 安装 Recoil
  2. 在根组件添加 RecoilRoot
  3. 配置 TypeScript 支持
  4. 与不同项目脚手架集成

下一步,让我们学习 核心概念,深入理解 Recoil 的工作原理。

最后更新:2026-03-28