React 状态管理库相关收录

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 支持
  • ✅ 中间件生态

基本用法

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

  1. 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",
};
  1. 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"));
  1. 结合 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();
  // ...
}
相关推荐
ssshooter1 小时前
Tauri 踩坑 appLink 修改后闪退
前端·ios·rust
刮涂层_赢大奖1 小时前
我把 AI 编程 Agent 变成了宝可梦,让它们在像素风办公室里跑来跑去
前端·typescript·claude
重庆穿山甲2 小时前
Java开发者的大模型入门:Spring AI组件全攻略(二)
前端·后端
重庆穿山甲2 小时前
Java开发者的大模型入门:Spring AI组件全攻略(一)
前端·后端
布列瑟农的星空2 小时前
前端都能看懂的rust入门教程(二)——函数和闭包
前端·后端·rust
晨米酱2 小时前
四、Prettier 编辑器集成指南
前端·代码规范
文心快码BaiduComate3 小时前
Comate 4.0新年全面焕新!底层重构、七大升级、复杂任务驾驭力跃升
前端·程序员·架构
怪可爱的地球人3 小时前
uni-app:5 步接入 vite-plugin-uni-pages,用 <route> 自动生成 pages.json
前端
前端Hardy3 小时前
告别 !important:现代 CSS 层叠控制指南,90% 的样式冲突其实不用它也能解
前端·vue.js·面试
前端Hardy3 小时前
Vue 3 性能优化的 5 个隐藏技巧,第 4 个连老手都未必知道
前端·vue.js·面试