性能优化 #
Recoil 的性能优势 #
Recoil 的设计本身就具有良好的性能特性:
- 细粒度订阅:组件只订阅需要的状态
- 自动缓存:Selector 自动缓存计算结果
- 最小化重渲染:状态变化只影响订阅的组件
选择正确的 Hook #
只读状态使用 useRecoilValue #
jsx
function DisplayName() {
const user = useRecoilValue(userState);
return <div>{user.name}</div>;
}
只写状态使用 useSetRecoilState #
jsx
function UpdateButton() {
const setUser = useSetRecoilState(userState);
return (
<button onClick={() => setUser({ name: 'New Name' })}>
Update
</button>
);
}
对比 #
jsx
function BadExample() {
const [user, setUser] = useRecoilState(userState);
return (
<button onClick={() => setUser({ name: 'New Name' })}>
Update
</button>
);
}
function GoodExample() {
const setUser = useSetRecoilState(userState);
return (
<button onClick={() => setUser({ name: 'New Name' })}>
Update
</button>
);
}
状态拆分 #
拆分大对象 #
jsx
const userState = atom({
key: 'user',
default: {
profile: { name: '', email: '' },
settings: { theme: 'light', language: 'en' },
preferences: { notifications: true },
},
});
function UserName() {
const user = useRecoilValue(userState);
return <div>{user.profile.name}</div>;
}
优化后:
jsx
const userProfileState = atom({
key: 'userProfile',
default: { name: '', email: '' },
});
const userSettingsState = atom({
key: 'userSettings',
default: { theme: 'light', language: 'en' },
});
const userPreferencesState = atom({
key: 'userPreferences',
default: { notifications: true },
});
function UserName() {
const profile = useRecoilValue(userProfileState);
return <div>{profile.name}</div>;
}
使用 atomFamily #
jsx
const todoFamily = atomFamily({
key: 'todo',
default: (id) => ({ id, text: '', completed: false }),
});
function TodoItem({ id }) {
const [todo, setTodo] = useRecoilState(todoFamily(id));
return (
<div>
<input
value={todo.text}
onChange={(e) => setTodo({ ...todo, text: e.target.value })}
/>
</div>
);
}
Selector 缓存 #
自动缓存 #
jsx
const expensiveSelector = selector({
key: 'expensive',
get: ({ get }) => {
const data = get(dataState);
return data.map(item => expensiveTransform(item));
},
});
缓存策略 #
jsx
const cachedSelector = selector({
key: 'cached',
get: ({ get }) => {
return computeExpensiveValue(get(dataState));
},
cachePolicy_UNSTABLE: {
eviction: 'lru',
maxSize: 100,
},
});
避免不必要的计算 #
条件返回 #
jsx
const optimizedSelector = selector({
key: 'optimized',
get: ({ get }) => {
const data = get(dataState);
if (data.length === 0) {
return [];
}
return data.map(expensiveTransform);
},
});
提前退出 #
jsx
const filteredSelector = selector({
key: 'filtered',
get: ({ get }) => {
const items = get(itemsState);
const filter = get(filterState);
if (filter === 'all') {
return items;
}
return items.filter(item => item.category === filter);
},
});
组件优化 #
使用 React.memo #
jsx
const TodoItem = React.memo(function TodoItem({ id }) {
const [todo, setTodo] = useRecoilState(todoFamily(id));
return (
<div>
<input
value={todo.text}
onChange={(e) => setTodo({ ...todo, text: e.target.value })}
/>
</div>
);
});
拆分组件 #
jsx
function UserCard({ userId }) {
const user = useRecoilValue(userQueryState(userId));
return (
<div>
<UserAvatar user={user} />
<UserInfo user={user} />
<UserActions userId={userId} />
</div>
);
}
const UserAvatar = React.memo(function UserAvatar({ user }) {
return <img src={user.avatar} alt={user.name} />;
});
const UserInfo = React.memo(function UserInfo({ user }) {
return (
<div>
<h3>{user.name}</h3>
<p>{user.email}</p>
</div>
);
});
function UserActions({ userId }) {
const setUser = useSetRecoilState(userQueryState(userId));
return (
<div>
<button onClick={() => setUser(prev => ({ ...prev, followed: true }))}>
Follow
</button>
</div>
);
}
批量更新 #
使用 useRecoilCallback #
jsx
function BatchUpdateButton() {
const updateAll = useRecoilCallback(({ set }) => () => {
set(firstNameState, 'John');
set(lastNameState, 'Doe');
set(emailState, 'john@example.com');
});
return <button onClick={updateAll}>Update All</button>;
}
使用 transact_UNSTABLE #
jsx
const batchUpdate = useRecoilCallback(({ transact_UNSTABLE }) => () => {
transact_UNSTABLE(({ set }) => {
set(firstNameState, 'John');
set(lastNameState, 'Doe');
set(emailState, 'john@example.com');
});
});
异步优化 #
预取数据 #
jsx
function usePrefetch(queryState) {
return useRecoilCallback(({ snapshot }) => async () => {
await snapshot.getPromise(queryState);
});
}
function UserListItem({ userId }) {
const prefetch = usePrefetch(userQueryState(userId));
return (
<div onMouseEnter={prefetch}>
User {userId}
</div>
);
}
并行请求 #
jsx
const parallelQueryState = selector({
key: 'parallelQuery',
get: async ({ get }) => {
const [users, posts, comments] = await Promise.all([
fetch('/api/users').then(r => r.json()),
fetch('/api/posts').then(r => r.json()),
fetch('/api/comments').then(r => r.json()),
]);
return { users, posts, comments };
},
});
性能监控 #
使用 useEffect 监控重渲染 #
jsx
function MyComponent() {
const value = useRecoilValue(myState);
useEffect(() => {
console.log('Component rendered:', Date.now());
});
return <div>{value}</div>;
}
使用 React DevTools Profiler #
jsx
<React.Profiler id="MyComponent" onRender={(id, phase, actualDuration) => {
console.log(`${id} ${phase} took ${actualDuration}ms`);
}}>
<MyComponent />
</React.Profiler>
常见性能陷阱 #
1. 在 Selector 中创建新对象 #
jsx
const badSelector = selector({
key: 'bad',
get: ({ get }) => {
const items = get(itemsState);
return { items };
},
});
const goodSelector = selector({
key: 'good',
get: ({ get }) => {
return get(itemsState);
},
});
2. 过度使用 useRecoilState #
jsx
function BadComponent() {
const [count, setCount] = useRecoilState(countState);
return <button onClick={() => setCount(c => c + 1)}>+</button>;
}
function GoodComponent() {
const setCount = useSetRecoilState(countState);
return <button onClick={() => setCount(c => c + 1)}>+</button>;
}
3. 不必要的依赖 #
jsx
const badSelector = selector({
key: 'bad',
get: ({ get }) => {
const allData = get(allDataState);
return allData.filter(item => item.active);
},
});
const goodSelector = selector({
key: 'good',
get: ({ get }) => {
const activeIds = get(activeIdsState);
return activeIds.map(id => get(itemFamily(id)));
},
});
性能优化检查清单 #
- [ ] 使用正确的 Hook(useRecoilValue、useSetRecoilState)
- [ ] 拆分大对象为多个 Atom
- [ ] 使用 atomFamily 管理列表项状态
- [ ] 利用 Selector 缓存
- [ ] 使用 React.memo 优化组件
- [ ] 批量更新状态
- [ ] 预取异步数据
- [ ] 避免在 Selector 中创建新对象
总结 #
性能优化的核心要点:
| 优化方式 | 说明 |
|---|---|
| 选择正确 Hook | 只读用 useRecoilValue,只写用 useSetRecoilState |
| 状态拆分 | 拆分大对象为多个 Atom |
| Selector 缓存 | 利用自动缓存,配置缓存策略 |
| 组件优化 | 使用 React.memo,拆分组件 |
| 批量更新 | 使用 useRecoilCallback 批量更新 |
下一步,让我们学习 项目结构,了解 Recoil 项目的代码组织规范。
最后更新:2026-03-28