React 状态管理:Redux/Zustand、项目优化

2 阅读3分钟

一、React 全局状态方案对比

方案学习成本样板代码体积适用
Context内置低频共享(主题、登录态)
Redux(RTK)较大大型项目、复杂状态流、团队规范
Zustand极少~1KB中小项目、快速上手
Jotai / MobX细粒度状态、响应式偏好

选型建议:小项目用 Context 或 Zustand;大项目、面试常考用 Redux Toolkit;需求简单别上重方案。


二、Redux 核心极简使用(RTK)

2.1 安装与创建 Store

npm install @reduxjs/toolkit react-redux
// store/counterSlice.js
import { createSlice } from "@reduxjs/toolkit";

const counterSlice = createSlice({
  name: "counter",
  initialState: { value: 0 },
  reducers: {
    increment: (state) => { state.value += 1; },          // RTK 内部用 Immer,可直接改
    add: (state, action) => { state.value += action.payload; },
  },
});

export const { increment, add } = counterSlice.actions;
export default counterSlice.reducer;
// store/index.js
import { configureStore } from "@reduxjs/toolkit";
import counterReducer from "./counterSlice";

export const store = configureStore({
  reducer: { counter: counterReducer },
});

2.2 注入与使用

// main.jsx
import { Provider } from "react-redux";
import { store } from "./store";

createRoot(document.getElementById("root")).render(
  <Provider store={store}>
    <App />
  </Provider>
);
// 组件中使用
import { useDispatch, useSelector } from "react-redux";
import { increment } from "@/store/counterSlice";

function Counter() {
  const count = useSelector((state) => state.counter.value);
  const dispatch = useDispatch();

  return <button onClick={() => dispatch(increment())}>计数:{count}</button>;
}
核心概念作用
configureStore创建 store(自动集成 devtools 中间件)
createSlice定义 state + reducers(自动生成 action)
useSelector读取 state(订阅变化自动重渲染)
useDispatch派发 action 触发更新

异步请求用 createAsyncThunk 写在 extraReducers 中;本处不展开,掌握上述四件套即可应对常规需求。


三、轻量方案 Zustand 快速上手

3.1 安装与定义 Store

npm install zustand
// store/userStore.js
import { create } from "zustand";

export const useUserStore = create((set, get) => ({
  user: null,
  token: localStorage.getItem("token") || "",

  // set:合并更新 state;get:读取当前 state
  login: (user) => {
    set({ user, token: "token-" + Date.now() });
    localStorage.setItem("token", "token-" + Date.now());
  },
  logout: () => set({ user: null, token: "" }),
}));

3.2 组件中使用

import { useUserStore } from "@/store/userStore";

function Profile() {
  // selector 按需订阅:只取用到的字段
  const user = useUserStore((s) => s.user);
  const login = useUserStore((s) => s.login);

  return (
    <div>
      {user ? <p>你好,{user.name}</p> : <button onClick={() => login({ name: "张三" })}>登录</button>}
    </div>
  );
}

3.3 Redux vs Zustand 快速对比

对比项Redux(RTK)Zustand
定义slice + reducer + actioncreate 一个函数搞定
读取useSelectorselector 函数
修改dispatch action直接调用 store 方法
学习成本较高极低
推荐场景大型/复杂项目中小项目、快速迭代

四、React 性能优化:memo、useMemo、useCallback

4.1 memo:组件级缓存

import { memo } from "react";

// props 不变时跳过重渲染
const ExpensiveList = memo(function ExpensiveList({ items }) {
  return <ul>{items.map((i) => <li key={i.id}>{i.name}</li>)}</ul>;
});

注意:memo 是浅比较 props;父组件重渲染但 props 引用不变时,子组件不重渲染。

4.2 useMemo:值缓存

import { useMemo } from "react";

function Report({ list }) {
  // 只有 list 变化时才重新计算(昂贵计算)
  const total = useMemo(
    () => list.reduce((sum, item) => sum + item.price, 0),
    [list]
  );

  return <p>合计:{total}</p>;
}

4.3 useCallback:函数缓存

import { useCallback } from "react";

function Parent() {
  // 函数引用稳定:配合 memo 子组件避免无谓重渲染
  const handleAdd = useCallback((id) => {
    console.log("add", id);
  }, []);

  return <Child onAdd={handleAdd} />;
}

4.4 三件套区别与选择

工具缓存对象配合 memo 生效典型场景
memo整个组件重渲染昂贵的子组件
useMemo计算结果大列表过滤、复杂运算
useCallback函数引用传给 memo 子组件的回调

4.5 什么时候不用优化

不必优化的情况原因
组件很轻、渲染快优化本身有开销(对比成本)
props 经常变化缓存命中率低
提前优化的代码先测量再优化("过早优化是万恶之源")

五、总结

  • 方案选型:Context(轻量低频)→ Zustand(中小项目)→ Redux(大型/面试);按复杂度选,别过度设计;
  • ReduxconfigureStore + createSlice + useSelector/useDispatch 四件套,Immer 允许直接改 state;
  • Zustandcreate + set/get,selector 按需订阅,零样板;
  • 优化:memo 缓存组件、useMemo 缓存值、useCallback 缓存函数,配合使用才有意义;
  • 原则:先测量后优化,缓存依赖写全,避免过早优化。