React 状态管理库相关收录
本文档总结了当前主流 React 状态管理库的核心特性、优缺点及使用模式,方便快速查阅和选型。
概览与选型指南
快速选型矩阵
| 库名 | 核心思想 | 适用场景 |
|---|---|---|
| Zustand | 极简单一 Store | 中小型项目、追求开发效率 |
| Redux (RTK) | 严格单向数据流 | 大型复杂应用、强可维护性 |
| Jotai | 原子化状态 | 复杂组件状态、细粒度控制 |
| MobX | 响应式编程 | 中大型项目、熟悉响应式编程 |
| Context API | 内置状态传递 | 低频更新的全局状态 |
选型考虑因素
-
项目规模
- 小型项目:Zustand、Jotai、Context API
- 大型项目:Redux Toolkit、MobX
-
团队熟悉度
- 熟悉 Flux 架构:Redux
- 偏好响应式:MobX
- 追求简洁:Zustand、Jotai
-
性能要求
- 高频更新:Zustand、Jotai、MobX
- 低频更新:Context API
-
TypeScript 支持
- 优秀:Zustand、Redux Toolkit、Jotai
- 良好:MobX
Zustand
核心特性
- ✅ 极简 API,学习成本低
- ✅ 无需 Provider 包裹
- ✅ 基于 Hook 的使用方式
- ✅ 自动不可变更新(内置 Immer)
- ✅ 卓越的性能(精确更新)
- ✅ 一流的 TypeScript 支持
- ✅ 中间件生态
基本用法
javascript
import { create } from "zustand";
// 创建 Store
const useBearStore = create((set, get) => ({
bears: 0,
fish: 10,
increasePopulation: () => set((state) => ({ bears: state.bears + 1 })),
removeAllBears: () => set({ bears: 0 }),
eatFishAndAddBear: async () => {
const response = await fetch("/api/add-bear");
const newBearCount = await response.json();
const currentFish = get().fish;
if (currentFish > 0) {
set({ bears: newBearCount, fish: currentFish - 1 });
}
},
}));
// 在组件中使用
function BearCounter() {
const bears = useBearStore((state) => state.bears); // 选择器订阅
const increasePopulation = useBearStore((state) => state.increasePopulation);
return (
<div>
<h1>{bears} around here ...</h1>
<button onClick={increasePopulation}>Add Bear</button>
</div>
);
}
Jotai
Jotai 的核心概念是原子(Atom),通过组合原子来构建状态。
js
import { atom, useAtom } from "jotai";
// 1. 创建原子
const countAtom = atom(0);
// 派生原子,用于计算衍生状态
const doubleCountAtom = atom((get) => get(countAtom) * 2);
// 2. 在组件中使用
function Counter() {
const [count, setCount] = useAtom(countAtom);
const [doubleCount] = useAtom(doubleCountAtom);
return (
<div>
<p>
{count} * 2 = {doubleCount}
</p>
<button onClick={() => setCount((c) => c + 1)}>one up</button>
</div>
);
}
Redux Toolkit (RTK)
RTK 是 Redux 官方推荐的、简化 Redux 使用的工具集,大幅减少了模板代码。
js
// 1. 使用RTK创建Slice
import { createSlice, configureStore } from "@reduxjs/toolkit";
const counterSlice = createSlice({
name: "counter",
initialState: { value: 0 },
reducers: {
incremented: (state) => {
state.value += 1;
}, // 内部使用Immer,可直接"突变"
decremented: (state) => {
state.value -= 1;
},
},
});
// 2. 创建Store
const store = configureStore({
reducer: counterSlice.reducer,
});
// 3. 在React组件中使用
import { useSelector, useDispatch } from "react-redux";
function Counter() {
const count = useSelector((state) => state.value);
const dispatch = useDispatch();
return (
<div>
<span>{count}</span>
<button onClick={() => dispatch(counterSlice.actions.incremented())}>
Increment
</button>
</div>
);
}
useReducer
useReducer 是 React 提供的一个内置 Hook,它是 useState 的替代方案,更适合管理复杂的状态逻辑。它借鉴了 Redux 的核心思想,但更加轻量化和内置化。
基本语法
js
const [state, dispatch] = useReducer(reducer, initialState);
基本用法
js
import { useReducer } from "react";
// 1. 定义 reducer 函数
function counterReducer(state, action) {
switch (action.type) {
case "increment":
return { count: state.count + 1 };
case "decrement":
return { count: state.count - 1 };
case "reset":
return { count: 0 };
case "set":
return { count: action.payload };
default:
throw new Error(`Unknown action type: ${action.type}`);
}
}
// 2. 在组件中使用
function Counter() {
const [state, dispatch] = useReducer(counterReducer, { count: 0 });
return (
<div>
<h1>Count: {state.count}</h1>
<button onClick={() => dispatch({ type: "increment" })}>+1</button>
<button onClick={() => dispatch({ type: "decrement" })}>-1</button>
<button onClick={() => dispatch({ type: "reset" })}>Reset</button>
<button onClick={() => dispatch({ type: "set", payload: 10 })}>
Set to 10
</button>
</div>
);
}
相对复杂用法
js
import { useReducer, useState } from "react";
// 初始状态
const initialState = {
todos: [],
filter: "all", // all, active, completed
};
// Reducer 函数
function todoReducer(state, action) {
switch (action.type) {
case "ADD_TODO":
return {
...state,
todos: [
...state.todos,
{
id: Date.now(),
text: action.payload,
completed: false,
},
],
};
case "TOGGLE_TODO":
return {
...state,
todos: state.todos.map((todo) =>
todo.id === action.payload
? { ...todo, completed: !todo.completed }
: todo
),
};
case "DELETE_TODO":
return {
...state,
todos: state.todos.filter((todo) => todo.id !== action.payload),
};
case "SET_FILTER":
return {
...state,
filter: action.payload,
};
case "CLEAR_COMPLETED":
return {
...state,
todos: state.todos.filter((todo) => !todo.completed),
};
default:
return state;
}
}
function TodoApp() {
const [state, dispatch] = useReducer(todoReducer, initialState);
const [inputValue, setInputValue] = useState("");
const addTodo = () => {
if (inputValue.trim()) {
dispatch({ type: "ADD_TODO", payload: inputValue });
setInputValue("");
}
};
// 根据筛选条件过滤 todos
const filteredTodos = state.todos.filter((todo) => {
if (state.filter === "active") return !todo.completed;
if (state.filter === "completed") return todo.completed;
return true;
});
return (
<div>
<h1>Todo App (useReducer)</h1>
<div>
<input
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
onKeyPress={(e) => e.key === "Enter" && addTodo()}
placeholder="Add a new todo..."
/>
<button onClick={addTodo}>Add</button>
</div>
<div>
<button
onClick={() => dispatch({ type: "SET_FILTER", payload: "all" })}
>
All
</button>
<button
onClick={() => dispatch({ type: "SET_FILTER", payload: "active" })}
>
Active
</button>
<button
onClick={() => dispatch({ type: "SET_FILTER", payload: "completed" })}
>
Completed
</button>
<button onClick={() => dispatch({ type: "CLEAR_COMPLETED" })}>
Clear Completed
</button>
</div>
<ul>
{filteredTodos.map((todo) => (
<li
key={todo.id}
style={{
textDecoration: todo.completed ? "line-through" : "none",
}}
>
<span
onClick={() =>
dispatch({ type: "TOGGLE_TODO", payload: todo.id })
}
>
{todo.text}
</span>
<button
onClick={() =>
dispatch({ type: "DELETE_TODO", payload: todo.id })
}
>
Delete
</button>
</li>
))}
</ul>
<div>
<p>Total: {state.todos.length}</p>
<p>Active: {state.todos.filter((t) => !t.completed).length}</p>
<p>Completed: {state.todos.filter((t) => t.completed).length}</p>
</div>
</div>
);
}
useReducer 最佳实践
- Action 类型常量
js
// actions.js
export const ActionTypes = {
ADD_TODO: "ADD_TODO",
TOGGLE_TODO: "TOGGLE_TODO",
DELETE_TODO: "DELETE_TODO",
SET_FILTER: "SET_FILTER",
CLEAR_COMPLETED: "CLEAR_COMPLETED",
};
- Action 创建函数
js
// actionCreators.js
export const addTodo = (text) => ({
type: ActionTypes.ADD_TODO,
payload: text,
});
export const toggleTodo = (id) => ({
type: ActionTypes.TOGGLE_TODO,
payload: id,
});
// 在组件中使用
dispatch(addTodo("Learn useReducer"));
- 结合 Context API 实现全局状态管理
js
import { createContext, useContext, useReducer } from "react";
const TodoContext = createContext();
export function TodoProvider({ children }) {
const [state, dispatch] = useReducer(todoReducer, initialState);
return (
<TodoContext.Provider value={{ state, dispatch }}>
{children}
</TodoContext.Provider>
);
}
export const useTodo = () => {
const context = useContext(TodoContext);
if (!context) {
throw new Error("useTodo must be used within a TodoProvider");
}
return context;
};
// 在任何子组件中使用
function TodoList() {
const { state, dispatch } = useTodo();
// ...
}