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优化
  • 状态不一致:确保所有状态更新都是纯函数
  • 竞态条件:使用防抖、节流或取消令牌
  • 内存泄漏:及时清理订阅和定时器