Atom基础 #

什么是 Atom? #

Atom 是 Recoil 中最小的状态单元,它代表一个可订阅、可修改的状态。可以把 Atom 想象成一个全局的 useState,但可以被任何组件访问。

text
┌─────────────────────────────────────────┐
│                 Atom                     │
├─────────────────────────────────────────┤
│  ┌─────────┐  ┌─────────┐  ┌─────────┐  │
│  │Component│  │Component│  │Component│  │
│  │    A    │  │    B    │  │    C    │  │
│  └────┬────┘  └────┬────┘  └────┬────┘  │
│       │            │            │       │
│       └────────────┼────────────┘       │
│                    │                    │
│              ┌─────▼─────┐              │
│              │   Atom    │              │
│              │  (状态源)  │              │
│              └───────────┘              │
└─────────────────────────────────────────┘

创建 Atom #

基本语法 #

jsx
import { atom } from 'recoil';

const myState = atom({
  key: 'myState',
  default: initialValue,
});

参数说明 #

参数 类型 必填 说明
key string 唯一标识符,全局唯一
default any 默认值,可以是任意类型

创建不同类型的 Atom #

jsx
import { atom } from 'recoil';

const countState = atom({
  key: 'countState',
  default: 0,
});

const textState = atom({
  key: 'textState',
  default: 'Hello',
});

const userState = atom({
  key: 'userState',
  default: {
    id: 1,
    name: 'John',
    email: 'john@example.com',
  },
});

const todoListState = atom({
  key: 'todoListState',
  default: [],
});

const isLoggedInState = atom({
  key: 'isLoggedInState',
  default: false,
});

使用 Atom #

useRecoilState - 读写状态 #

useRecoilState 类似于 useState,返回一个数组:[value, setValue]

jsx
import { useRecoilState } from 'recoil';

function Counter() {
  const [count, setCount] = useRecoilState(countState);
  
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <button onClick={() => setCount(count - 1)}>Decrement</button>
    </div>
  );
}

useRecoilValue - 只读状态 #

当组件只需要读取状态,不需要修改时,使用 useRecoilValue

jsx
import { useRecoilValue } from 'recoil';

function CountDisplay() {
  const count = useRecoilValue(countState);
  return <p>Current count: {count}</p>;
}

useSetRecoilState - 只写状态 #

当组件只需要修改状态,不需要读取时,使用 useSetRecoilState

jsx
import { useSetRecoilState } from 'recoil';

function IncrementButton() {
  const setCount = useSetRecoilState(countState);
  
  return (
    <button onClick={() => setCount(c => c + 1)}>
      Increment
    </button>
  );
}

useResetRecoilState - 重置状态 #

重置 Atom 到默认值:

jsx
import { useResetRecoilState } from 'recoil';

function ResetButton() {
  const resetCount = useResetRecoilState(countState);
  
  return <button onClick={resetCount}>Reset</button>;
}

更新状态 #

直接设置值 #

jsx
const [count, setCount] = useRecoilState(countState);

setCount(10);

使用函数更新 #

jsx
setCount(prev => prev + 1);

更新对象状态 #

jsx
const [user, setUser] = useRecoilState(userState);

setUser({
  ...user,
  name: 'Jane',
});

setUser(prev => ({
  ...prev,
  email: 'jane@example.com',
}));

更新数组状态 #

jsx
const [todos, setTodos] = useRecoilState(todoListState);

setTodos([...todos, newTodo]);

setTodos(todos.filter(todo => todo.id !== id));

setTodos(todos.map(todo => 
  todo.id === id ? { ...todo, completed: true } : todo
));

实战示例:Todo List #

jsx
import { atom, useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';

const todoListState = atom({
  key: 'todoListState',
  default: [],
});

const todoFilterState = atom({
  key: 'todoFilterState',
  default: 'all',
});

function TodoList() {
  const [todos, setTodos] = useRecoilState(todoListState);
  
  const addTodo = (text) => {
    setTodos([
      ...todos,
      {
        id: Date.now(),
        text,
        completed: false,
      },
    ]);
  };
  
  const toggleTodo = (id) => {
    setTodos(todos.map(todo =>
      todo.id === id ? { ...todo, completed: !todo.completed } : todo
    ));
  };
  
  const deleteTodo = (id) => {
    setTodos(todos.filter(todo => todo.id !== id));
  };
  
  return (
    <div>
      <TodoInput onAdd={addTodo} />
      <ul>
        {todos.map(todo => (
          <li key={todo.id}>
            <input
              type="checkbox"
              checked={todo.completed}
              onChange={() => toggleTodo(todo.id)}
            />
            <span style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}>
              {todo.text}
            </span>
            <button onClick={() => deleteTodo(todo.id)}>Delete</button>
          </li>
        ))}
      </ul>
    </div>
  );
}

function TodoInput({ onAdd }) {
  const [text, setText] = useState('');
  
  const handleSubmit = (e) => {
    e.preventDefault();
    if (text.trim()) {
      onAdd(text);
      setText('');
    }
  };
  
  return (
    <form onSubmit={handleSubmit}>
      <input
        value={text}
        onChange={(e) => setText(e.target.value)}
        placeholder="Add todo..."
      />
      <button type="submit">Add</button>
    </form>
  );
}

Atom 的默认值 #

静态默认值 #

jsx
const countState = atom({
  key: 'countState',
  default: 0,
});

对象默认值 #

jsx
const userState = atom({
  key: 'userState',
  default: {
    name: '',
    email: '',
    age: 0,
  },
});

使用另一个 Atom 作为默认值 #

jsx
const baseCountState = atom({
  key: 'baseCountState',
  default: 10,
});

const countState = atom({
  key: 'countState',
  default: baseCountState,
});

Atom Effects #

Atom Effects 是在 Atom 创建时执行的副作用函数:

jsx
const countState = atom({
  key: 'countState',
  default: 0,
  effects: [
    ({ onSet }) => {
      onSet((newValue, oldValue) => {
        console.log(`Count changed from ${oldValue} to ${newValue}`);
      });
    },
    ({ setSelf, onSet }) => {
      const savedValue = localStorage.getItem('count');
      if (savedValue != null) {
        setSelf(JSON.parse(savedValue));
      }
      
      onSet((newValue) => {
        localStorage.setItem('count', JSON.stringify(newValue));
      });
    },
  ],
});

Effects API #

jsx
effects: [
  ({
    node,
    trigger,
    setSelf,
    resetSelf,
    onSet,
    getPromise,
    getLoadable,
    getInfo_UNSTABLE,
  }) => {
    
  },
]
方法 说明
setSelf 设置初始值
resetSelf 重置到默认值
onSet 监听值变化
getPromise 异步获取其他状态
getLoadable 同步获取其他状态

持久化示例 #

jsx
const localStorageEffect = (key) => ({ setSelf, onSet }) => {
  const savedValue = localStorage.getItem(key);
  if (savedValue != null) {
    setSelf(JSON.parse(savedValue));
  }
  
  onSet((newValue) => {
    localStorage.setItem(key, JSON.stringify(newValue));
  });
};

const todoListState = atom({
  key: 'todoListState',
  default: [],
  effects: [
    localStorageEffect('todo_list'),
  ],
});

性能优化 #

选择合适的 Hook #

jsx
function OptimizedComponent() {
  const setCount = useSetRecoilState(countState);
  
  return <button onClick={() => setCount(c => c + 1)}>+</button>;
}

使用 useSetRecoilState 而不是 useRecoilState,组件不会在 count 变化时重渲染。

避免不必要的订阅 #

jsx
function UserName() {
  const user = useRecoilValue(userState);
  return <span>{user.name}</span>;
}

function UserEmail() {
  const user = useRecoilValue(userState);
  return <span>{user.email}</span>;
}

如果 name 和 email 经常独立变化,应该拆分为独立的 Atom:

jsx
const userNameState = atom({ key: 'userName', default: '' });
const userEmailState = atom({ key: 'userEmail', default: '' });

总结 #

本章学习了 Atom 的基础用法:

Hook 用途
useRecoilState 读写状态
useRecoilValue 只读状态
useSetRecoilState 只写状态
useResetRecoilState 重置状态

下一步,让我们学习 Atom配置,深入了解 Atom 的高级配置选项。

最后更新:2026-03-28