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();
  // ...
}
相关推荐
程序员Sunday5 小时前
TypeScript 的 any、unknown、never 有什么区别?
前端·面试·typescript
朱涛的自习室5 小时前
70 美金的 Beyond Compare,我让 Gemini 4 和 DeepSeek 造个开源免费版(Day 2)
android·前端·人工智能
码艺-Alimjan6 小时前
Tauri 源码备份 · 打包 & 解压 总结,源码收集之路
前端·javascript·vue.js
小马不起床6 小时前
零基础玩转 FastAPI_11:前端后台管理页面
前端·状态模式·fastapi
子非鱼a8 小时前
【文件上传】一个普普通通的edu16
前端
美狐美颜SDK开放平台8 小时前
直播APP如何实现美白滤镜功能?视频美颜SDK技术开发方案详解
前端·数据库·人工智能·音视频·美颜sdk·直播美颜sdk·视频美颜sdk
pride.li9 小时前
第03章 Python 教程-基础语法:注释与变量
服务器·前端·后端·python·算法·计算机视觉
屏什么录9 小时前
电脑如何录屏幕视频和声音?从工具到代码,7 种方案帮你彻底搞定
前端·音视频开发
用户360055579009 小时前
Kestrel_VLLM_CUDA -09 · full-GPU decode:单 token 全设备
前端
kyriewen9 小时前
我上手了 Vite+ 1.0:Node 不用自己装,lint 却翻车了
前端·javascript·程序员