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();
  // ...
}
相关推荐
假如让我当三天老蒯1 分钟前
Composables和Utils的区别(自学用)
前端
kungggyoyoyo4 分钟前
从0开发一套geo优化软件:系统定位与整体架构
前端
用户713874229006 分钟前
PKCE 的 S256 算法深度剖析:从协议设计到密码学原理
前端
闪闪发光得欧6 分钟前
StreamTokenizer的源码分析和使用方法详细分析
前端
李剑一7 分钟前
华为一面就问网络安全?面试官:请简述一下 XSS/CSRF 的攻击面与前端侧的防护
前端·面试
竹林81810 分钟前
被合约事件搞到失眠?我踩了三天坑,终于写出一份监听智能合约事件的实战指南
前端·javascript
用户0595401744612 分钟前
把 AI 记忆验证从手工 Log 换成 Pytest+Mem0,上下文丢失 bug 减少 90%
前端·css
艾利克斯冰25 分钟前
TypeScript 静态类型入门教程:可选静态类型与类型推导详
前端·javascript·typescript
GuWenyue29 分钟前
告别命名混乱!5步掌握BEM规范,写出易维护的前端页面
前端·javascript·面试
小林ixn30 分钟前
BEM 命名规范与 CSS 重置:打造优雅的按钮页面实战
前端·css