React 状态管理

状态管理是构建可维护、可扩展的React应用的核心。选择合适的状态管理方案能极大提升开发效率和代码质量。

什么是状态管理?

状态管理是指在React应用中存储、组织和更新数据的方式。良好的状态管理应确保数据流清晰、组件通信高效、调试方便。

组件状态

useState, useReducer

上下文状态

Context API

全局状态

Redux, Zustand等

服务器状态

React Query, SWR

状态管理方案概览

最流行

Redux

JavaScript应用的可预测状态容器

  • 单一数据源
  • 状态只读
  • 纯函数修改
  • 时间旅行调试
  • 中间件支持
学习曲线: 高 | 代码量: 多 | 生态: 丰富
轻量级

Zustand

小型、快速、可扩展的状态管理

  • 极简API
  • 无需Provider
  • TypeScript友好
  • 支持中间件
  • 体积小巧
学习曲线: 低 | 代码量: 少 | 生态: 一般
响应式

MobX

简单、可扩展的状态管理

  • 响应式编程
  • 最小化样板代码
  • 自动追踪依赖
  • 面向对象友好
  • 装饰器支持
学习曲线: 中 | 代码量: 中 | 生态: 成熟
实验性

Recoil

Facebook实验性状态管理

  • 基于Hooks
  • 原子化状态
  • 派生状态
  • 异步支持
  • Facebook开发
学习曲线: 中 | 代码量: 中 | 生态: 发展
原子化

Jotai

基于原子的状态管理

  • 极简API
  • 原子化设计
  • 零样板代码
  • TypeScript优先
  • 可组合性高
学习曲线: 低 | 代码量: 很少 | 生态: 较小
内置

Context API

React内置状态共享

  • 无需额外依赖
  • 简单易用
  • 组件树传递
  • 适合中小应用
  • 与Hooks集成
学习曲线: 低 | 代码量: 中等 | 生态: React内置

Redux基础

1

创建Store

import { createStore } from 'redux';

// 初始状态
const initialState = {
  count: 0,
  user: null,
  todos: []
};

// Reducer函数
const rootReducer = (state = initialState, action) => {
  switch (action.type) {
    case 'INCREMENT':
      return { ...state, count: state.count + 1 };
    case 'DECREMENT':
      return { ...state, count: state.count - 1 };
    case 'SET_USER':
      return { ...state, user: action.payload };
    case 'ADD_TODO':
      return { ...state, todos: [...state.todos, action.payload] };
    default:
      return state;
  }
};

// 创建Store
const store = createStore(rootReducer);
2

Action创建器

// Action创建函数
const increment = () => ({
  type: 'INCREMENT'
});

const decrement = () => ({
  type: 'DECREMENT'
});

const setUser = (user) => ({
  type: 'SET_USER',
  payload: user
});

const addTodo = (text) => ({
  type: 'ADD_TODO',
  payload: {
    id: Date.now(),
    text,
    completed: false
  }
});
3

React集成 (React-Redux)

import { Provider, useSelector, useDispatch } from 'react-redux';

// 提供Store给整个应用
function App() {
  return (
    <Provider store={store}>
      <Counter />
      <UserProfile />
    </Provider>
  );
}

// 在组件中使用
function Counter() {
  const count = useSelector(state => state.count);
  const dispatch = useDispatch();

  return (
    <div>
      <p>计数: {count}</p>
      <button onClick={() => dispatch(increment())}>增加</button>
      <button onClick={() => dispatch(decrement())}>减少</button>
    </div>
  );
}
4

Redux Toolkit (现代Redux)

import { configureStore, createSlice } from '@reduxjs/toolkit';

// 创建Slice
const counterSlice = createSlice({
  name: 'counter',
  initialState: { value: 0 },
  reducers: {
    increment: state => {
      state.value += 1;
    },
    decrement: state => {
      state.value -= 1;
    },
    incrementByAmount: (state, action) => {
      state.value += action.payload;
    }
  }
});

// 导出Actions和Reducer
export const { increment, decrement, incrementByAmount } = counterSlice.actions;
export default counterSlice.reducer;

// 配置Store
const store = configureStore({
  reducer: {
    counter: counterSlice.reducer
  }
});

Zustand示例

import create from 'zustand';

// 创建Store
const useStore = create((set) => ({
  // 状态
  bears: 0,
  fish: 0,
  user: null,

  // Actions
  increasePopulation: () => set((state) => ({ bears: state.bears + 1 })),
  removeAllBears: () => set({ bears: 0 }),

  // 异步Action
  fetchUser: async (userId) => {
    const response = await fetch(`/api/users/${userId}`);
    const user = await response.json();
    set({ user });
  },

  // 复杂更新
  updateUser: (updates) =>
    set((state) => ({
      user: { ...state.user, ...updates }
    }))
}));

// 在组件中使用
function BearCounter() {
  const bears = useStore((state) => state.bears);
  const increasePopulation = useStore((state) => state.increasePopulation);

  return (
    <div>
      <h1>熊的数量: {bears}</h1>
      <button onClick={increasePopulation}>增加一只熊</button>
    </div>
  );
}

// 使用中间件
const useStoreWithMiddleware = create(
  persist(
    (set, get) => ({
      todos: [],
      addTodo: (text) =>
        set({ todos: [...get().todos, { text, completed: false }] }),
    }),
    {
      name: 'todo-storage', // localStorage key
    }
  )
);

状态管理演示

购物车状态管理

购物车状态

总计: $0

商品数量: 0

状态变更日志
状态管理控制台已就绪...

状态管理选择指南

决策树

问题1: 应用规模有多大?
推荐方案矩阵
需求 推荐方案 备选方案
快速原型/小型应用 Context API Zustand
需要时间旅行调试 Redux MobX
极简主义/讨厌样板代码 Zustand Jotai
响应式/OOP风格 MobX Redux
Facebook生态/实验性 Recoil Context API

状态管理模式

单一数据源

整个应用的状态存储在一个对象树中,便于调试和跟踪

// Redux和Flux模式
const appState = {
  user: {...},
  cart: {...},
  ui: {...}
};
原子化状态

状态被分解为最小的原子单位,可独立订阅和更新

// Recoil和Jotai
const countState = atom({
  key: 'countState',
  default: 0
});
双向数据绑定

状态变更自动反映到UI,UI操作自动更新状态

// MobX和Vuex
@observable count = 0;

@action increment() {
  this.count++;
}
不可变数据

状态不能被修改,只能通过创建新状态来更新

// Redux和Immer
return {
  ...state,
  count: state.count + 1
};

状态管理最佳实践

1. 合理划分状态

  • 本地状态:使用useState(如表单输入)
  • 共享状态:使用Context或状态管理库
  • 服务器状态:使用React Query或SWR
  • URL状态:使用React Router管理

2. 避免状态冗余

// 不好:存储冗余状态
const [todos, setTodos] = useState([]);
const [completedCount, setCompletedCount] = useState(0);

// 好:计算派生状态
const todos = useSelector(state => state.todos);
const completedCount = useMemo(() =>
  todos.filter(todo => todo.completed).length,
  [todos]
);

3. 使用选择器优化性能

// 创建记忆化选择器
import { createSelector } from '@reduxjs/toolkit';

const selectTodos = state => state.todos;

export const selectCompletedTodos = createSelector(
  [selectTodos],
  todos => todos.filter(todo => todo.completed)
);

// 在组件中使用
const completedTodos = useSelector(selectCompletedTodos);

4. 异步状态管理

// 使用Redux Thunk
const fetchUser = (userId) => async (dispatch) => {
  dispatch({ type: 'FETCH_USER_REQUEST' });

  try {
    const response = await api.getUser(userId);
    dispatch({ type: 'FETCH_USER_SUCCESS', payload: response });
  } catch (error) {
    dispatch({ type: 'FETCH_USER_FAILURE', payload: error });
  }
};

// 使用RTK Query
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';

export const api = createApi({
  baseQuery: fetchBaseQuery({ baseUrl: '/api' }),
  endpoints: (builder) => ({
    getUser: builder.query({
      query: (id) => `users/${id}`,
    }),
  }),
});

服务器状态管理

// 使用React Query
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';

function UserList() {
  const queryClient = useQueryClient();

  // 查询数据
  const { data: users, isLoading, error } = useQuery({
    queryKey: ['users'],
    queryFn: () => fetch('/api/users').then(res => res.json()),
    staleTime: 5 * 60 * 1000, // 5分钟
  });

  // 创建数据
  const createUser = useMutation({
    mutationFn: (newUser) =>
      fetch('/api/users', {
        method: 'POST',
        body: JSON.stringify(newUser),
      }),
    onSuccess: () => {
      // 使users查询失效,触发重新获取
      queryClient.invalidateQueries({ queryKey: ['users'] });
    },
  });

  // 更新数据
  const updateUser = useMutation({
    mutationFn: ({ id, ...updates }) =>
      fetch(`/api/users/${id}`, {
        method: 'PUT',
        body: JSON.stringify(updates),
      }),
    onMutate: async (newUser) => {
      // 乐观更新
      await queryClient.cancelQueries({ queryKey: ['users'] });
      const previousUsers = queryClient.getQueryData(['users']);

      queryClient.setQueryData(['users'], (old) =>
        old.map(user => user.id === newUser.id ? newUser : user)
      );

      return { previousUsers };
    },
    onError: (err, newUser, context) => {
      // 回滚乐观更新
      queryClient.setQueryData(['users'], context.previousUsers);
    },
  });

  if (isLoading) return 
加载中...
; if (error) return
错误: {error.message}
; return (
{users.map(user => (
{user.name}
))}
); }

状态管理工具对比

特性 Redux Zustand MobX Context API
学习曲线
代码量 很少 中等 中等
性能 中等
调试工具 优秀 良好 良好 基础
TypeScript支持 优秀 优秀 良好 良好
中间件支持 丰富 支持 支持
社区生态 极大 增长中 成熟 React内置
适用场景 大型企业应用 中小型应用 OOP风格应用 简单状态共享
常见陷阱与解决方案:
  • 过度使用全局状态:将状态保持在需要它的最低层级
  • 状态更新性能问题:使用选择器、memo和useCallback优化
  • 状态不一致:确保所有状态更新都是纯函数
  • 竞态条件:使用防抖、节流或取消令牌
  • 内存泄漏:及时清理订阅和定时器