useRecoilState #
什么是 useRecoilState? #
useRecoilState 是 Recoil 提供的核心 Hook,类似于 React 的 useState,但用于读写 Recoil 状态。它返回一个数组:[value, setValue]。
jsx
const [value, setValue] = useRecoilState(state);
基本用法 #
读取和更新状态 #
jsx
import { atom, useRecoilState } from 'recoil';
const countState = atom({
key: 'countState',
default: 0,
});
function Counter() {
const [count, setCount] = useRecoilState(countState);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
与 useState 的对比 #
jsx
function CounterWithUseState() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
function CounterWithRecoil() {
const [count, setCount] = useRecoilState(countState);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
主要区别:
| 特性 | useState | useRecoilState |
|---|---|---|
| 作用域 | 组件内部 | 全局 |
| 状态共享 | 需要手动传递 | 自动共享 |
| 持久化 | 组件卸载后丢失 | 可配置持久化 |
| 调试 | React DevTools | Recoil DevTools |
更新状态的方式 #
直接设置值 #
jsx
const [count, setCount] = useRecoilState(countState);
setCount(10);
setCount(0);
使用函数更新 #
jsx
setCount(prev => prev + 1);
setCount(prev => prev * 2);
setCount(prev => Math.max(0, prev - 1));
条件更新 #
jsx
const increment = () => {
setCount(prev => {
if (prev >= 10) {
console.log('Max reached');
return prev;
}
return prev + 1;
});
};
更新对象状态 #
替换整个对象 #
jsx
const [user, setUser] = useRecoilState(userState);
setUser({
id: 1,
name: 'John',
email: 'john@example.com',
});
更新部分属性 #
jsx
setUser(prev => ({
...prev,
name: 'Jane',
}));
setUser(prev => ({
...prev,
email: 'jane@example.com',
}));
嵌套对象更新 #
jsx
const [settings, setSettings] = useRecoilState(settingsState);
setSettings(prev => ({
...prev,
theme: {
...prev.theme,
primaryColor: '#007bff',
},
}));
更新数组状态 #
添加元素 #
jsx
const [todos, setTodos] = useRecoilState(todoListState);
setTodos(prev => [...prev, newTodo]);
setTodos(prev => [newTodo, ...prev]);
删除元素 #
jsx
setTodos(prev => prev.filter(todo => todo.id !== id));
更新元素 #
jsx
setTodos(prev => prev.map(todo =>
todo.id === id ? { ...todo, completed: true } : todo
));
排序 #
jsx
setTodos(prev => [...prev].sort((a, b) => a.priority - b.priority));
使用 Selector #
useRecoilState 也可以用于可写 Selector:
jsx
import { atom, selector, useRecoilState } from 'recoil';
const tempCelsiusState = atom({
key: 'tempCelsius',
default: 25,
});
const tempFahrenheitState = selector({
key: 'tempFahrenheit',
get: ({ get }) => get(tempCelsiusState) * 9 / 5 + 32,
set: ({ set }, value) => set(tempCelsiusState, (value - 32) * 5 / 9),
});
function TemperatureInput() {
const [fahrenheit, setFahrenheit] = useRecoilState(tempFahrenheitState);
return (
<input
type="number"
value={fahrenheit}
onChange={(e) => setFahrenheit(Number(e.target.value))}
/>
);
}
性能优化 #
避免不必要的重渲染 #
如果只需要读取或写入,使用专门的 Hook:
jsx
function OptimizedComponent() {
const setCount = useSetRecoilState(countState);
return <button onClick={() => setCount(c => c + 1)}>+</button>;
}
function DisplayOnly() {
const count = useRecoilValue(countState);
return <div>{count}</div>;
}
使用函数更新避免依赖 #
jsx
function BadExample() {
const [count, setCount] = useRecoilState(countState);
const increment = useCallback(() => {
setCount(count + 1);
}, [count, setCount]);
return <button onClick={increment}>+</button>;
}
function GoodExample() {
const [count, setCount] = useRecoilState(countState);
const increment = useCallback(() => {
setCount(c => c + 1);
}, [setCount]);
return <button onClick={increment}>+</button>;
}
实战示例:表单处理 #
jsx
import { atom, useRecoilState } from 'recoil';
const formState = atom({
key: 'formState',
default: {
username: '',
email: '',
password: '',
confirmPassword: '',
},
});
function Form() {
const [form, setForm] = useRecoilState(formState);
const handleChange = (field) => (e) => {
setForm(prev => ({
...prev,
[field]: e.target.value,
}));
};
const handleSubmit = (e) => {
e.preventDefault();
console.log('Submit:', form);
};
return (
<form onSubmit={handleSubmit}>
<input
value={form.username}
onChange={handleChange('username')}
placeholder="Username"
/>
<input
type="email"
value={form.email}
onChange={handleChange('email')}
placeholder="Email"
/>
<input
type="password"
value={form.password}
onChange={handleChange('password')}
placeholder="Password"
/>
<input
type="password"
value={form.confirmPassword}
onChange={handleChange('confirmPassword')}
placeholder="Confirm Password"
/>
<button type="submit">Submit</button>
</form>
);
}
实战示例:购物车 #
jsx
import { atom, useRecoilState } from 'recoil';
const cartState = atom({
key: 'cartState',
default: [],
});
function useCart() {
const [cart, setCart] = useRecoilState(cartState);
const addItem = (item) => {
setCart(prev => {
const existing = prev.find(i => i.id === item.id);
if (existing) {
return prev.map(i =>
i.id === item.id ? { ...i, quantity: i.quantity + 1 } : i
);
}
return [...prev, { ...item, quantity: 1 }];
});
};
const removeItem = (itemId) => {
setCart(prev => prev.filter(i => i.id !== itemId));
};
const updateQuantity = (itemId, quantity) => {
if (quantity <= 0) {
removeItem(itemId);
return;
}
setCart(prev => prev.map(i =>
i.id === itemId ? { ...i, quantity } : i
));
};
const clearCart = () => {
setCart([]);
};
const total = cart.reduce((sum, item) => sum + item.price * item.quantity, 0);
return {
cart,
addItem,
removeItem,
updateQuantity,
clearCart,
total,
};
}
function ShoppingCart() {
const { cart, updateQuantity, removeItem, total } = useCart();
return (
<div>
{cart.map(item => (
<div key={item.id}>
<span>{item.name}</span>
<input
type="number"
value={item.quantity}
onChange={(e) => updateQuantity(item.id, Number(e.target.value))}
/>
<button onClick={() => removeItem(item.id)}>Remove</button>
</div>
))}
<div>Total: ${total}</div>
</div>
);
}
TypeScript 支持 #
tsx
import { atom, useRecoilState } from 'recoil';
interface User {
id: number;
name: string;
email: string;
}
const userState = atom<User | null>({
key: 'userState',
default: null,
});
function UserProfile() {
const [user, setUser] = useRecoilState(userState);
const updateName = (name: string) => {
if (user) {
setUser({ ...user, name });
}
};
if (!user) return <div>Not logged in</div>;
return (
<div>
<input
value={user.name}
onChange={(e) => updateName(e.target.value)}
/>
</div>
);
}
总结 #
useRecoilState 的核心要点:
| 用法 | 说明 |
|---|---|
[value, setValue] |
返回值和设置函数 |
| 直接设置 | setValue(newValue) |
| 函数更新 | setValue(prev => newValue) |
| 对象更新 | 使用展开运算符 |
| 数组更新 | 使用 map/filter/spread |
下一步,让我们学习 useRecoilValue,了解只读状态的 Hook。
最后更新:2026-03-28