React 状态管理:选哪个?
这个问题我被问过不下十次。说实话,没有标准答案,但我可以分享一下这几年的观察。
先说结论
小型项目用 Context + useReducer 就够了。中大型项目,Zustand 或 Jotai。Redux?除非你团队已经用熟了,否则别折腾。
Context 的问题
Context 本身没问题,问题在于怎么用。很多人这么写:
const AppContext = createContext();
function AppProvider({ children }) {
const [user, setUser] = useState(null);
const [theme, setTheme] = useState('light');
const [cart, setCart] = useState([]);
return (
<AppContext.Provider value={{ user, setUser, theme, setTheme, cart, setCart }}>
{children}
</AppContext.Provider>
);
}
然后任何一处状态变了,所有消费这个 Context 的组件都会重渲染。这就是所谓的”Context 性能问题”。
解决方案:拆分 Context。
const UserContext = createContext();
const ThemeContext = createContext();
const CartContext = createContext();
// 各自独立,互不影响
或者用 useMemo 优化一下 value。
Zustand 怎么样
用了一段时间,感觉挺好的。主要优点:
- 代码量少,没有模板代码
- 不需要 Provider 包裹
- 可以在组件外使用
import { create } from 'zustand';
const useStore = create((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
}));
// 任何地方都能用
useStore.getState().increment();
但有个问题,就是开发工具不如 Redux 那么完善。调试的时候有点不方便。
Jotai 的原子化思路
Jotai 是另一个思路,把状态拆成原子:
import { atom, useAtom } from 'jotai';
const countAtom = atom(0);
function Counter() {
const [count, setCount] = useAtom(countAtom);
return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}
非常像 React 原生的 useState,只是状态可以在组件间共享。我个人挺喜欢这种风格的。
Redux Toolkit
如果你团队已经在用 Redux,那 Redux Toolkit 确实比以前方便多了。但学习曲线还是在的,光是搞清楚 slice、thunk、middleware 就够喝一壶的。
新项目的话,个人觉得没必要。
最后
工具是次要的,关键是想清楚状态属于哪一层:
- 组件内部状态 → useState
- 组件树共享状态 → Context / Zustand / Jotai
- 服务端状态 → React Query / SWR
把服务端状态也塞进全局状态管理,是我见过最常见的坑。