Skip to content
📖预计阅读时长:0 分钟字数:0

React 状态管理

进阶篇第 3 章:掌握 React 状态管理方案,从 Context 到专业状态库。

返回 React学习路线 | 上一章 React-08-自定义Hooks | 下一章 React-10-TypeScript实战


一、状态管理概述

1.1 何时需要状态管理

  • 多个组件共享状态
  • 状态需要跨层级传递
  • 复杂的状态更新逻辑
  • 需要状态持久化或同步

1.2 方案对比

方案复杂度适用场景特点
useState组件内状态最简单
Context⭐⭐跨组件共享内置方案
Zustand⭐⭐中小型应用简洁、轻量
Jotai⭐⭐原子化状态细粒度更新
Redux Toolkit⭐⭐⭐大型应用生态完善

二、Context 进阶

2.1 Context + useReducer

jsx
// contexts/CartContext.jsx
import { createContext, useContext, useReducer } from 'react';

const CartContext = createContext(null);

const initialState = { items: [], total: 0 };

function cartReducer(state, action) {
  switch (action.type) {
    case 'ADD_ITEM':
      return {
        items: [...state.items, action.payload],
        total: state.total + action.payload.price,
      };
    case 'REMOVE_ITEM':
      const item = state.items.find(i => i.id === action.payload);
      return {
        items: state.items.filter(i => i.id !== action.payload),
        total: state.total - (item?.price || 0),
      };
    case 'CLEAR':
      return initialState;
    default:
      return state;
  }
}

export function CartProvider({ children }) {
  const [state, dispatch] = useReducer(cartReducer, initialState);

  const addItem = (item) => dispatch({ type: 'ADD_ITEM', payload: item });
  const removeItem = (id) => dispatch({ type: 'REMOVE_ITEM', payload: id });
  const clearCart = () => dispatch({ type: 'CLEAR' });

  return (
    <CartContext.Provider value=\{\{ ...state, addItem, removeItem, clearCart \}\}>
      {children}
    </CartContext.Provider>
  );
}

export function useCart() {
  const context = useContext(CartContext);
  if (!context) throw new Error('useCart must be used within CartProvider');
  return context;
}

2.2 Context 性能优化

jsx
// 拆分 Context 避免不必要的重渲染
const CartStateContext = createContext(null);
const CartDispatchContext = createContext(null);

export function CartProvider({ children }) {
  const [state, dispatch] = useReducer(cartReducer, initialState);

  return (
    <CartStateContext.Provider value={state}>
      <CartDispatchContext.Provider value={dispatch}>
        {children}
      </CartDispatchContext.Provider>
    </CartStateContext.Provider>
  );
}

// 只需要状态的组件
export function useCartState() {
  return useContext(CartStateContext);
}

// 只需要 dispatch 的组件
export function useCartDispatch() {
  return useContext(CartDispatchContext);
}

三、Zustand(推荐)

3.1 基本用法

jsx
import { create } from 'zustand';

// 创建 store
const useStore = create((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
  decrement: () => set((state) => ({ count: state.count - 1 })),
  reset: () => set({ count: 0 }),
}));

// 使用
function Counter() {
  const { count, increment, decrement } = useStore();
  
  return (
    <div>
      <p>{count}</p>
      <button onClick={increment}>+</button>
      <button onClick={decrement}>-</button>
    </div>
  );
}

// 选择性订阅(性能优化)
function Display() {
  const count = useStore((state) => state.count);
  return <p>{count}</p>;
}

3.2 异步操作

jsx
const useUserStore = create((set) => ({
  user: null,
  loading: false,
  error: null,
  
  fetchUser: async (id) => {
    set({ loading: true, error: null });
    try {
      const response = await fetch(`/api/users/${id}`);
      const user = await response.json();
      set({ user, loading: false });
    } catch (error) {
      set({ error: error.message, loading: false });
    }
  },
}));

3.3 持久化

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

const useStore = create(
  persist(
    (set) => ({
      theme: 'light',
      setTheme: (theme) => set({ theme }),
    }),
    {
      name: 'app-storage', // localStorage key
    }
  )
);

四、Jotai

4.1 原子化状态

jsx
import { atom, useAtom } from 'jotai';

// 创建原子
const countAtom = atom(0);
const doubleCountAtom = atom((get) => get(countAtom) * 2);

// 使用
function Counter() {
  const [count, setCount] = useAtom(countAtom);
  const [doubleCount] = useAtom(doubleCountAtom);

  return (
    <div>
      <p>Count: {count}</p>
      <p>Double: {doubleCount}</p>
      <button onClick={() => setCount(c => c + 1)}>+</button>
    </div>
  );
}

4.2 异步原子

jsx
const userAtom = atom(async () => {
  const response = await fetch('/api/user');
  return response.json();
});

function User() {
  const [user] = useAtom(userAtom);
  return <p>{user.name}</p>;
}

五、Redux Toolkit

5.1 创建 Slice

jsx
// store/slices/counterSlice.js
import { createSlice } from '@reduxjs/toolkit';

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;
    },
  },
});

export const { increment, decrement, incrementByAmount } = counterSlice.actions;
export default counterSlice.reducer;

5.2 配置 Store

jsx
// store/index.js
import { configureStore } from '@reduxjs/toolkit';
import counterReducer from './slices/counterSlice';

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

// App.jsx
import { Provider } from 'react-redux';
import { store } from './store';

function App() {
  return (
    <Provider store={store}>
      <Counter />
    </Provider>
  );
}

5.3 使用 Hooks

jsx
import { useSelector, useDispatch } from 'react-redux';
import { increment, decrement } from './store/slices/counterSlice';

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

  return (
    <div>
      <p>{count}</p>
      <button onClick={() => dispatch(increment())}>+</button>
      <button onClick={() => dispatch(decrement())}>-</button>
    </div>
  );
}

六、方案选择建议

场景推荐方案
简单共享状态Context
中小型应用Zustand(首选)
细粒度状态Jotai
大型应用/团队协作Redux Toolkit
服务端状态React Query / SWR

下一步


#React #状态管理 #Zustand #Redux #Jotai