React 状态管理库相关收录

本文档总结了当前主流 React 状态管理库的核心特性、优缺点及使用模式,方便快速查阅和选型。


概览与选型指南

快速选型矩阵

库名核心思想适用场景
Zustand极简单一 Store中小型项目、追求开发效率
Redux (RTK)严格单向数据流大型复杂应用、强可维护性
Jotai原子化状态复杂组件状态、细粒度控制
MobX响应式编程中大型项目、熟悉响应式编程
Context API内置状态传递低频更新的全局状态

选型考虑因素

  1. 项目规模

    • 小型项目:Zustand、Jotai、Context API
    • 大型项目:Redux Toolkit、MobX
  2. 团队熟悉度

    • 熟悉 Flux 架构:Redux
    • 偏好响应式:MobX
    • 追求简洁:Zustand、Jotai
  3. 性能要求

    • 高频更新:Zustand、Jotai、MobX
    • 低频更新:Context API
  4. TypeScript 支持

    • 优秀:Zustand、Redux Toolkit、Jotai
    • 良好:MobX

Zustand

核心特性

  • ✅ 极简 API,学习成本低
  • ✅ 无需 Provider 包裹
  • ✅ 基于 Hook 的使用方式
  • ✅ 自动不可变更新(内置 Immer)
  • ✅ 卓越的性能(精确更新)
  • ✅ 一流的 TypeScript 支持
  • ✅ 中间件生态

基本用法

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),通过组合原子来构建状态。

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 使用的工具集,大幅减少了模板代码。

// 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 的核心思想,但更加轻量化和内置化。

基本语法

const [state, dispatch] = useReducer(reducer, initialState);

基本用法

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>
  );
}

相对复杂用法

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 最佳实践

  1. Action 类型常量
// 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",
};
  1. Action 创建函数
// 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"));
  1. 结合 Context API 实现全局状态管理
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();
  // ...
}
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐