React面试宝典【Part6:状态管理生态】

2026-08-03 React,面试

1. Redux 核心原理

核心思想:单向数据流
严格的闭环流程:

  1. View 触发 → dispatch(action)
  2. action 进入中间件链(异步/日志等)
  3. reducer 接收 (state, action),纯函数计算新 state
  4. store 更新 → 订阅组件重新渲染

三大原则

  • 单一数据源:一个应用一个 store
  • state 只读:只能通过 dispatch(action) 修改
  • reducer 必须是纯函数:无副作用、相同输入必相同输出

中间件原理

  • 本质:包装、增强 dispatch
  • 在 action 到达 reducer 之前做拦截处理
  • 典型:
    • redux-thunk:让 action 可以是函数,支持异步
    • redux-saga:用 generator 管理复杂异步流
    • redux-logger:打印 action/state 变化

现状

  • 优势:可预测、时间旅行调试、生态极全
  • 劣势:样板代码多、写法繁琐
  • 趋势:中后台/超大型项目仍在用;中小项目基本被替代

2. 主流状态管理横向对比

Redux

  • 风格:函数式、不可变、集中式
  • 优点:可预测、调试强、标准化、适合多人协作大型项目
  • 缺点:繁琐、boilerplate 重
  • 适用:超复杂业务、中后台系统、需要强规范的团队

MobX

  • 风格:响应式、可变数据、OOP 风格
  • 优点:写法简单、自动追踪依赖、更新精准
  • 缺点:黑盒、调试难、可预测性弱
  • 适用:追求开发速度、复杂交互客户端应用

Zustand(当前最火)

  • 风格:极简、无 Context、轻量、不可变可选
  • 优点:
    • 代码极少,几行一个全局状态
    • 不依赖 Context,无嵌套地狱
    • 细粒度选取状态,不会无脑重渲染
    • 支持异步、中间件、持久化
  • 缺点:生态不如 Redux 丰富
  • 适用:绝大多数现代 React 项目首选

Jotai

  • 风格:原子化状态(Atomic)
  • 优点:
    • 状态以原子为单位,天然细粒度订阅
    • 不会出现“改一个状态全组件刷新”
    • 组合原子非常灵活
  • 缺点:心智模型稍高
  • 适用:追求极致性能、频繁更新的全局状态

Recoil

  • 风格:Facebook 官方、原子化
  • 类似 Jotai,但更重、API 更多
  • 现在使用率不如 Jotai/Zustand

3. 一张表速记对比

方案 核心特点 可变/不可变 渲染机制 上手难度 主流地位
Redux 单向数据流、可预测 不可变 手动选择+广播 传统巨头
MobX 响应式、自动追踪 可变 精准更新 老牌强势
Zustand 极简、无Context 可选 手动精准选取 极低 当下顶流
Jotai 原子化、细粒度 不可变 原子级精准 高性能首选

4. 选型建议

  • 中小型项目 → Zustand 无脑选
  • 极致性能、频繁更新 → Jotai
  • 超大型复杂团队、强规范 → Redux Toolkit
  • 快速开发、不在意调试黑盒 → MobX

5. 总结

  • Redux 是规范与可预测
  • MobX 是便捷与响应式
  • Zustand 是简单与实用
  • Jotai 是精准与性能

目前前端趋势:轻量、原子化、脱离 Context、减少重渲染,Zustand + Jotai 基本占据主流。


Zustand 简单示例

无 Context、无 Provider、无繁琐模板

1. 安装

npm install zustand
# or
yarn add zustand

2. 定义 store

// store/useCountStore.js
import { create } from 'zustand';

// 一句话创建全局状态
const useCountStore = create((set) => ({
  count: 0,

  inc: () => set((state) => ({ count: state.count + 1 })),
  dec: () => set((state) => ({ count: state.count - 1 })),

  // 异步也完全无压力
  asyncInc: async () => {
    await new Promise(resolve => setTimeout(resolve, 500));
    set((state) => ({ count: state.count + 1 }));
  },
}));

export default useCountStore;

3. 组件里使用

import useCountStore from './store/useCountStore';

function Counter() {
  // 只订阅需要的状态,精准不重渲染
  const count = useCountStore((state) => state.count);
  const inc = useCountStore((state) => state.inc);
  const asyncInc = useCountStore((state) => state.asyncInc);

  return (
    <div>
      <h2>count: {count}</h2>
      <button onClick={inc}>+1</button>
      <button onClick={asyncInc}>异步+1</button>
    </div>
  );
}

export default Counter;

4. 另一个组件共享状态

import useCountStore from './store/useCountStore';

function AnotherComponent() {
  // 跨组件自动同步
  const count = useCountStore((state) => state.count);
  return <p>另一个组件:{count}</p>;
}

对比优势

  • 不用包裹 App 顶层 Provider
  • 不会因为一个状态变,所有组件都重渲染
  • 订阅精准:(state) => state.count 只监听这一个字段
  • 同步/异步写法完全一致
  • 体积超小,API 极少,3 分钟上手

进阶

持久化(刷新不丢)

import { create } from 'zustand';
import { persist } from 'zustand/middleware';

const useUserStore = create(
  persist(
    (set) => ({
      user: null,
      setUser: (user) => set({ user }),
    }),
    { name: 'user-storage' } // localStorage key
  )
);

切片模式(大型项目拆分 store)

const useStore = create((set) => ({
  ...useCountStore.getState(),
  ...useUserStore.getState(),
}));