Skip to content

React 状态管理方案详解

本文档详细介绍 React 生态中主流的状态管理方案,包括 useReducer、Redux、MobX 和 Zustand,涵盖它们的原理、使用方法、适用场景和优缺点对比。

  1. useReducer
  2. Redux
  3. MobX
  4. Zustand
  5. 方案对比总结

1. useReducer

1.1 原理

useReducer 是 React 内置的 Hook,它借鉴了 Redux 的设计理念,是 useState 的替代方案。

核心原理:

State + Action = New State

useReducer 使用纯函数(reducer)来管理状态更新逻辑:

  1. Reducer 函数:接收当前 state 和 action,返回新的 state
  2. Dispatch 函数:发送 action 触发状态更新
  3. 初始状态:定义状态的初始值

工作流程:

Component → dispatch(action) → reducer(state, action) → newState → Component Re-render

1.2 基础使用

jsx
import { useReducer } from 'react'

// 定义 reducer 函数
function reducer(state, action) {
  switch (action.type) {
    case 'INCREMENT':
      return { count: state.count + 1 }
    case 'DECREMENT':
      return { count: state.count - 1 }
    case 'RESET':
      return { count: 0 }
    case 'SET_VALUE':
      return { count: action.payload }
    default:
      throw new Error(`Unknown action type: ${action.type}`)
  }
}

function Counter() {
  // useReducer(reducer, initialState)
  const [state, dispatch] = useReducer(reducer, { count: 0 })

  return (
    <div>
      <p>Count: {state.count}</p>
      <button onClick={() => dispatch({ type: 'INCREMENT' })}>+1</button>
      <button onClick={() => dispatch({ type: 'DECREMENT' })}>-1</button>
      <button onClick={() => dispatch({ type: 'RESET' })}>Reset</button>
      <button onClick={() => dispatch({ type: 'SET_VALUE', payload: 10 })}>
        Set to 10
      </button>
    </div>
  )
}

1.3 进阶使用:复杂状态管理

jsx
import { useReducer } from 'react'

// 复杂状态结构
const initialState = {
  user: null,
  loading: false,
  error: null,
  notifications: []
}

// 复杂 reducer
function appReducer(state, action) {
  switch (action.type) {
    case 'FETCH_USER_START':
      return { ...state, loading: true, error: null }

    case 'FETCH_USER_SUCCESS':
      return {
        ...state,
        loading: false,
        user: action.payload,
        notifications: [
          ...state.notifications,
          { type: 'success', message: '用户加载成功' }
        ]
      }

    case 'FETCH_USER_ERROR':
      return {
        ...state,
        loading: false,
        error: action.payload,
        notifications: [
          ...state.notifications,
          { type: 'error', message: action.payload }
        ]
      }

    case 'CLEAR_NOTIFICATION':
      return {
        ...state,
        notifications: state.notifications.filter((_, i) => i !== action.index)
      }

    case 'LOGOUT':
      return { ...initialState }

    default:
      return state
  }
}

function UserProfile() {
  const [state, dispatch] = useReducer(appReducer, initialState)

  const fetchUser = async userId => {
    dispatch({ type: 'FETCH_USER_START' })
    try {
      const response = await fetch(`/api/users/${userId}`)
      const user = await response.json()
      dispatch({ type: 'FETCH_USER_SUCCESS', payload: user })
    } catch (error) {
      dispatch({ type: 'FETCH_USER_ERROR', payload: error.message })
    }
  }

  return (
    <div>
      {state.loading && <p>Loading...</p>}
      {state.error && <p>Error: {state.error}</p>}
      {state.user && <p>User: {state.user.name}</p>}

      {state.notifications.map((notification, index) => (
        <div key={index} className={`notification ${notification.type}`}>
          {notification.message}
          <button
            onClick={() => dispatch({ type: 'CLEAR_NOTIFICATION', index })}
          >
            ×
          </button>
        </div>
      ))}

      <button onClick={() => fetchUser(1)}>Load User</button>
      <button onClick={() => dispatch({ type: 'LOGOUT' })}>Logout</button>
    </div>
  )
}

1.4 结合 Context 实现全局状态

jsx
import { createContext, useContext, useReducer } from 'react'

// 创建 Context
const StateContext = createContext(null)
const DispatchContext = createContext(null)

// Provider 组件
function AppProvider({ children }) {
  const [state, dispatch] = useReducer(appReducer, initialState)

  return (
    <StateContext.Provider value={state}>
      <DispatchContext.Provider value={dispatch}>
        {children}
      </DispatchContext.Provider>
    </StateContext.Provider>
  )
}

// 自定义 Hooks
function useAppState() {
  const context = useContext(StateContext)
  if (!context) {
    throw new Error('useAppState must be used within AppProvider')
  }
  return context
}

function useAppDispatch() {
  const context = useContext(DispatchContext)
  if (!context) {
    throw new Error('useAppDispatch must be used within AppProvider')
  }
  return context
}

// 使用示例
function UserName() {
  const state = useAppState()
  return <span>{state.user?.name}</span>
}

function LoginButton() {
  const dispatch = useAppDispatch()

  const handleLogin = () => {
    dispatch({ type: 'FETCH_USER_SUCCESS', payload: { name: 'John' } })
  }

  return <button onClick={handleLogin}>Login</button>
}

// App 根组件
function App() {
  return (
    <AppProvider>
      <UserName />
      <LoginButton />
    </AppProvider>
  )
}

1.5 使用场景

场景适用性
组件内部复杂状态逻辑✅ 非常适合
表单状态管理✅ 适合
多步向导/流程控制✅ 适合
全局状态管理⚠️ 需配合 Context
大型应用架构⚠️ 需要额外封装

1.6 优缺点

优点:

  • 内置 Hook:无需安装额外依赖
  • 可预测性:状态更新逻辑集中在 reducer 中,易于追踪和调试
  • 可测试性:reducer 是纯函数,易于单元测试
  • 适合复杂逻辑:比 useState 更适合管理复杂的状态转换
  • 性能优化:可以配合 useMemo、useCallback 优化渲染

缺点:

  • 样板代码:需要编写 reducer、action types 等
  • 局部作用域:默认只能在组件内部使用,跨组件共享需要 Context
  • 无中间件:不支持异步操作的中间件机制
  • 调试工具:相比 Redux,调试工具支持较弱

2. Redux

2.1 原理

Redux 是一个独立的 JavaScript 状态管理库,遵循单向数据流不可变状态原则。

三大原则:

  1. 单一数据源:整个应用的 state 存储在一个 store 中
  2. State 是只读的:唯一改变 state 的方式是触发 action
  3. 使用纯函数修改:通过 reducer 函数处理 action 并返回新 state

核心概念:

┌─────────────────────────────────────────────────────────┐
│                        Redux Store                       │
│  ┌─────────────────────────────────────────────────┐    │
│  │                   State                          │    │
│  └─────────────────────────────────────────────────┘    │
│                         ▲                               │
│                         │                               │
│  ┌──────────────────────┴──────────────────────────┐   │
│  │                   Reducer                        │   │
│  │         (state, action) => newState             │   │
│  └─────────────────────────────────────────────────┘    │
│                         ▲                               │
│                         │                               │
│  ┌──────────────────────┴──────────────────────────┐   │
│  │              Dispatch(action)                    │   │
│  └─────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────┘

数据流:

Action → Middleware → Reducer → New State → UI Update

2.2 Redux Toolkit 使用(推荐)

Redux Toolkit (RTK) 是官方推荐的 Redux 开发方式,大幅简化了 Redux 的使用。

安装:

bash
npm install @reduxjs/toolkit react-redux

基础配置:

jsx
// store.js
import { configureStore, createSlice } from '@reduxjs/toolkit'

// 创建 slice(包含 reducer 和 actions)
const counterSlice = createSlice({
  name: 'counter',
  initialState: {
    value: 0,
    status: 'idle'
  },
  reducers: {
    increment: state => {
      state.value += 1 // RTK 使用 Immer,可以直接修改
    },
    decrement: state => {
      state.value -= 1
    },
    incrementByAmount: (state, action) => {
      state.value += action.payload
    },
    reset: state => {
      state.value = 0
    }
  },
  // 异步操作使用 createAsyncThunk
  extraReducers: builder => {
    builder
      .addCase(fetchCount.pending, state => {
        state.status = 'loading'
      })
      .addCase(fetchCount.fulfilled, (state, action) => {
        state.status = 'idle'
        state.value = action.payload
      })
      .addCase(fetchCount.rejected, state => {
        state.status = 'failed'
      })
  }
})

// 异步 action
export const fetchCount = createAsyncThunk(
  'counter/fetchCount',
  async amount => {
    const response = await fetch(`/api/count?amount=${amount}`)
    return response.json()
  }
)

// 导出 actions
export const { increment, decrement, incrementByAmount, reset } =
  counterSlice.actions

// 创建 store
export const store = configureStore({
  reducer: {
    counter: counterSlice.reducer
  }
})

在 React 中使用:

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

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

// Counter.js
import { useSelector, useDispatch } from 'react-redux'
import {
  increment,
  decrement,
  incrementByAmount,
  reset,
  fetchCount
} from './store'

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

  return (
    <div>
      <p>Count: {count}</p>
      <p>Status: {status}</p>

      <button onClick={() => dispatch(increment())}>+1</button>
      <button onClick={() => dispatch(decrement())}>-1</button>
      <button onClick={() => dispatch(incrementByAmount(5))}>+5</button>
      <button onClick={() => dispatch(reset())}>Reset</button>
      <button onClick={() => dispatch(fetchCount(10))}>Fetch Count</button>
    </div>
  )
}

2.3 完整项目结构示例

src/
├── store/
│   ├── index.js           # store 配置
│   ├── slices/
│   │   ├── userSlice.js   # 用户状态
│   │   ├── cartSlice.js   # 购物车状态
│   │   └── uiSlice.js     # UI 状态
│   └── middleware/
│       └── logger.js      # 自定义中间件
├── hooks/
│   └── redux.js           # 类型化的 hooks
└── App.js

userSlice.js 示例:

jsx
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'

// 异步登录
export const loginUser = createAsyncThunk(
  'user/login',
  async ({ username, password }, { rejectWithValue }) => {
    try {
      const response = await fetch('/api/login', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ username, password })
      })

      if (!response.ok) {
        throw new Error('Login failed')
      }

      return await response.json()
    } catch (error) {
      return rejectWithValue(error.message)
    }
  }
)

const userSlice = createSlice({
  name: 'user',
  initialState: {
    user: null,
    token: null,
    status: 'idle', // 'idle' | 'loading' | 'succeeded' | 'failed'
    error: null
  },
  reducers: {
    logout: state => {
      state.user = null
      state.token = null
      state.status = 'idle'
      state.error = null
    },
    updateUser: (state, action) => {
      state.user = { ...state.user, ...action.payload }
    }
  },
  extraReducers: builder => {
    builder
      .addCase(loginUser.pending, state => {
        state.status = 'loading'
        state.error = null
      })
      .addCase(loginUser.fulfilled, (state, action) => {
        state.status = 'succeeded'
        state.user = action.payload.user
        state.token = action.payload.token
      })
      .addCase(loginUser.rejected, (state, action) => {
        state.status = 'failed'
        state.error = action.payload
      })
  }
})

export const { logout, updateUser } = userSlice.actions
export default userSlice.reducer

store/index.js:

jsx
import { configureStore } from '@reduxjs/toolkit'
import userReducer from './slices/userSlice'
import cartReducer from './slices/cartSlice'
import uiReducer from './slices/uiSlice'

export const store = configureStore({
  reducer: {
    user: userReducer,
    cart: cartReducer,
    ui: uiReducer
  },
  middleware: getDefaultMiddleware =>
    getDefaultMiddleware({
      serializableCheck: false
    }).concat(loggerMiddleware),
  devTools: process.env.NODE_ENV !== 'production'
})

2.4 使用场景

场景适用性
大型复杂应用✅ 非常适合
需要严格状态管理✅ 非常适合
团队协作开发✅ 适合
需要时间旅行调试✅ 非常适合
服务端渲染✅ 适合
小型简单应用❌ 过于复杂

2.5 优缺点

优点:

  • 可预测性:单向数据流,状态变化可追踪
  • 调试工具强大:Redux DevTools 支持时间旅行调试
  • 中间件生态:丰富的中间件支持(redux-thunk、redux-saga 等)
  • 社区成熟:大量文档、教程和解决方案
  • 服务端渲染:良好的 SSR 支持
  • 代码规范:强制性的代码结构,利于团队协作

缺点:

  • 样板代码多:即使使用 RTK,仍有一定样板代码
  • 学习曲线:概念较多,新手需要时间理解
  • 过度设计:小型项目使用 Redux 可能过度
  • 性能考量:需要合理使用 selector 避免不必要的渲染

3. MobX

3.1 原理

MobX 采用响应式编程范式,通过可观察状态(Observable State)和自动追踪依赖实现状态管理。

核心概念:

  1. Observable State(可观察状态):被 MobX 追踪的状态
  2. Computed Values(计算值):派生状态,自动缓存
  3. Reactions(反应):状态变化时的副作用
  4. Actions(动作):修改状态的方法

工作原理:

┌─────────────────────────────────────────────────────────┐
│                    MobX 响应式系统                        │
│                                                          │
│  ┌──────────────┐      ┌──────────────┐                 │
│  │  Observable  │      │   Computed   │                 │
│  │    State     │─────▶│    Value     │                 │
│  └──────────────┘      └──────────────┘                 │
│         │                     │                          │
│         │                     │                          │
│         ▼                     ▼                          │
│  ┌─────────────────────────────────────┐                │
│  │            Reactions                │                │
│  │   (自动更新 UI / 执行副作用)          │                │
│  └─────────────────────────────────────┘                │
│                                                          │
└─────────────────────────────────────────────────────────┘

依赖追踪机制: MobX 在组件渲染时自动追踪使用的 observable 属性,当这些属性变化时,组件自动重新渲染。

3.2 安装

bash
npm install mobx mobx-react-lite

3.3 基础使用

jsx
import { makeAutoObservable } from 'mobx'
import { observer } from 'mobx-react-lite'

// Store 类
class CounterStore {
  count = 0

  constructor() {
    // 自动将所有属性和方法转换为 observable/action
    makeAutoObservable(this)
  }

  // Actions
  increment() {
    this.count += 1
  }

  decrement() {
    this.count -= 1
  }

  reset() {
    this.count = 0
  }

  // Computed Values(计算属性)
  get doubleCount() {
    return this.count * 2
  }

  get isPositive() {
    return this.count > 0
  }
}

// 创建 store 实例
const counterStore = new CounterStore()

// 观察者组件
const Counter = observer(() => {
  return (
    <div>
      <p>Count: {counterStore.count}</p>
      <p>Double: {counterStore.doubleCount}</p>
      <p>Is Positive: {counterStore.isPositive ? 'Yes' : 'No'}</p>

      <button onClick={() => counterStore.increment()}>+1</button>
      <button onClick={() => counterStore.decrement()}>-1</button>
      <button onClick={() => counterStore.reset()}>Reset</button>
    </div>
  )
})

3.4 完整应用示例

jsx
import { makeAutoObservable, runInAction } from 'mobx'
import { observer } from 'mobx-react-lite'
import { createContext, useContext } from 'react'

// ==================== Stores ====================

// 用户 Store
class UserStore {
  user = null
  token = localStorage.getItem('token')
  loading = false
  error = null

  constructor() {
    makeAutoObservable(this)
  }

  get isLoggedIn() {
    return !!this.token && !!this.user
  }

  async login(username, password) {
    this.loading = true
    this.error = null

    try {
      const response = await fetch('/api/login', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ username, password })
      })

      const data = await response.json()

      // 异步操作中使用 runInAction
      runInAction(() => {
        this.user = data.user
        this.token = data.token
        this.loading = false
        localStorage.setItem('token', data.token)
      })
    } catch (error) {
      runInAction(() => {
        this.error = error.message
        this.loading = false
      })
    }
  }

  logout() {
    this.user = null
    this.token = null
    localStorage.removeItem('token')
  }

  updateUser(updates) {
    this.user = { ...this.user, ...updates }
  }
}

// 购物车 Store
class CartStore {
  items = []

  constructor() {
    makeAutoObservable(this)
  }

  get totalItems() {
    return this.items.reduce((sum, item) => sum + item.quantity, 0)
  }

  get totalPrice() {
    return this.items.reduce((sum, item) => sum + item.price * item.quantity, 0)
  }

  get hasItems() {
    return this.items.length > 0
  }

  addItem(product) {
    const existingItem = this.items.find(item => item.id === product.id)

    if (existingItem) {
      existingItem.quantity += 1
    } else {
      this.items.push({ ...product, quantity: 1 })
    }
  }

  removeItem(productId) {
    this.items = this.items.filter(item => item.id !== productId)
  }

  updateQuantity(productId, quantity) {
    const item = this.items.find(item => item.id === productId)
    if (item) {
      if (quantity <= 0) {
        this.removeItem(productId)
      } else {
        item.quantity = quantity
      }
    }
  }

  clearCart() {
    this.items = []
  }
}

// Root Store(组合所有 stores)
class RootStore {
  constructor() {
    this.userStore = new UserStore()
    this.cartStore = new CartStore()
  }
}

// ==================== Context Setup ====================

const StoreContext = createContext(null)

function StoreProvider({ children }) {
  const store = new RootStore()
  return <StoreContext.Provider value={store}>{children}</StoreContext.Provider>
}

function useStore() {
  const store = useContext(StoreContext)
  if (!store) {
    throw new Error('useStore must be used within StoreProvider')
  }
  return store
}

// ==================== Components ====================

// 登录表单
const LoginForm = observer(() => {
  const { userStore } = useStore()

  const handleSubmit = e => {
    e.preventDefault()
    const formData = new FormData(e.target)
    userStore.login(formData.get('username'), formData.get('password'))
  }

  if (userStore.loading) {
    return <p>Logging in...</p>
  }

  return (
    <form onSubmit={handleSubmit}>
      {userStore.error && <p style={{ color: 'red' }}>{userStore.error}</p>}
      <input name='username' placeholder='Username' />
      <input name='password' type='password' placeholder='Password' />
      <button type='submit'>Login</button>
    </form>
  )
})

// 用户信息
const UserInfo = observer(() => {
  const { userStore, cartStore } = useStore()

  if (!userStore.isLoggedIn) {
    return <LoginForm />
  }

  return (
    <div>
      <p>Welcome, {userStore.user?.name}!</p>
      <p>Cart Items: {cartStore.totalItems}</p>
      <button onClick={() => userStore.logout()}>Logout</button>
    </div>
  )
})

// 购物车
const Cart = observer(() => {
  const { cartStore } = useStore()

  if (!cartStore.hasItems) {
    return <p>Your cart is empty</p>
  }

  return (
    <div>
      <h3>Shopping Cart</h3>
      {cartStore.items.map(item => (
        <div key={item.id}>
          <span>{item.name}</span>
          <span> x {item.quantity}</span>
          <span> = ${item.price * item.quantity}</span>
          <button onClick={() => cartStore.removeItem(item.id)}>Remove</button>
        </div>
      ))}
      <p>Total: ${cartStore.totalPrice}</p>
      <button onClick={() => cartStore.clearCart()}>Clear Cart</button>
    </div>
  )
})

// 商品列表
const ProductList = observer(() => {
  const { cartStore } = useStore()

  const products = [
    { id: 1, name: 'Product A', price: 10 },
    { id: 2, name: 'Product B', price: 20 },
    { id: 3, name: 'Product C', price: 30 }
  ]

  return (
    <div>
      <h3>Products</h3>
      {products.map(product => (
        <div key={product.id}>
          <span>
            {product.name} - ${product.price}
          </span>
          <button onClick={() => cartStore.addItem(product)}>
            Add to Cart
          </button>
        </div>
      ))}
    </div>
  )
})

// ==================== App ====================

function App() {
  return (
    <StoreProvider>
      <UserInfo />
      <ProductList />
      <Cart />
    </StoreProvider>
  )
}

3.5 MobX 核心概念详解

jsx
import {
  makeAutoObservable,
  makeObservable,
  observable,
  action,
  computed,
  autorun,
  reaction,
  when,
  runInAction
} from 'mobx'

// 方式一:makeAutoObservable(推荐)
class Store1 {
  value = 0

  constructor() {
    makeAutoObservable(this)
  }
}

// 方式二:makeObservable(更细粒度控制)
class Store2 {
  value = 0

  constructor() {
    makeObservable(this, {
      value: observable,
      increment: action,
      doubleValue: computed
    })
  }

  increment() {
    this.value += 1
  }

  get doubleValue() {
    return this.value * 2
  }
}

// Reactions 示例
const store = new Store1()

// autorun: 立即执行,依赖变化时重新执行
autorun(() => {
  console.log('Value changed:', store.value)
})

// reaction: 更精细的控制,可指定追踪什么和执行什么
reaction(
  () => store.value, // 追踪的数据
  (value, prevValue) => {
    // 变化时执行的副作用
    console.log(`Value changed from ${prevValue} to ${value}`)
  }
)

// when: 条件满足时执行一次
when(
  () => store.value > 10, // 条件
  () => {
    console.log('Value is greater than 10!')
  }
)

// 异步操作处理
class AsyncStore {
  data = null
  loading = false

  constructor() {
    makeAutoObservable(this)
  }

  async fetchData() {
    this.loading = true

    const response = await fetch('/api/data')
    const data = await response.json()

    // 方式一:runInAction
    runInAction(() => {
      this.data = data
      this.loading = false
    })
  }

  // 方式二:使用 flow(推荐用于复杂异步)
  *fetchDataWithFlow() {
    this.loading = true

    try {
      const response = yield fetch('/api/data')
      const data = yield response.json()

      this.data = data
      this.loading = false
    } catch (error) {
      this.loading = false
      throw error
    }
  }
}

3.6 使用场景

场景适用性
面向对象编程风格✅ 非常适合
复杂领域模型✅ 非常适合
需要细粒度响应✅ 非常适合
快速原型开发✅ 适合
需要自动依赖追踪✅ 非常适合
函数式编程偏好❌ 不太适合

3.7 优缺点

优点:

  • 编写直观:可直接修改状态,无需 reducer/action
  • 自动依赖追踪:无需手动声明依赖关系
  • 细粒度响应:只有真正使用的状态变化才触发更新
  • 面向对象:适合 OOP 思维的开发者
  • 计算值缓存:computed 自动缓存,性能优化
  • 样板代码少:相比 Redux,代码更简洁

缺点:

  • 魔法行为:响应式系统有一定"魔法",调试需要理解原理
  • 可变状态:与 React 不可变理念不同,可能造成困惑
  • 调试工具:调试工具不如 Redux DevTools 强大
  • 学习曲线:需要理解 Observable、Reaction 等概念
  • TypeScript 支持:虽然支持,但配置相对复杂

4. Zustand

4.1 原理

Zustand 是一个极简的状态管理库,基于 Hooks发布-订阅模式

核心原理:

  1. Store:一个包含 state 和 actions 的对象
  2. Selector:选择性地订阅状态的一部分
  3. 订阅机制:状态变化时通知订阅者

工作流程:

┌─────────────────────────────────────────────────────────┐
│                    Zustand Store                         │
│                                                          │
│  ┌─────────────────────────────────────────────────┐    │
│  │                   State                          │    │
│  │  { count: 0, user: null, ... }                  │    │
│  └─────────────────────────────────────────────────┘    │
│                         │                               │
│                         ▼                               │
│  ┌─────────────────────────────────────────────────┐    │
│  │              Listeners (订阅者)                   │    │
│  │  [component1, component2, ...]                  │    │
│  └─────────────────────────────────────────────────┘    │
│                                                          │
│  setState(newState) → 通知所有订阅者                     │
│                                                          │
└─────────────────────────────────────────────────────────┘

特点:

  • 无需 Provider 包裹
  • 基于 Hooks,使用简单
  • 极小的包体积(~1KB)
  • 支持中间件

4.2 安装

bash
npm install zustand

4.3 基础使用

jsx
import { create } from 'zustand'

// 创建 store
const useCounterStore = create((set, get) => ({
  // State
  count: 0,

  // Actions
  increment: () => set(state => ({ count: state.count + 1 })),

  decrement: () => set(state => ({ count: state.count - 1 })),

  incrementByAmount: amount =>
    set(state => ({
      count: state.count + amount
    })),

  reset: () => set({ count: 0 }),

  // 使用 get() 获取当前状态
  logCurrentCount: () => {
    console.log('Current count:', get().count)
  }
}))

// 使用组件
function Counter() {
  // 选择性订阅(只有 count 变化时才重新渲染)
  const count = useCounterStore(state => state.count)
  const { increment, decrement, reset } = useCounterStore()

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>+1</button>
      <button onClick={decrement}>-1</button>
      <button onClick={reset}>Reset</button>
    </div>
  )
}

4.4 完整应用示例

jsx
import { create } from 'zustand'
import { persist, devtools, immer } from 'zustand/middleware'

// ==================== User Store ====================

const useUserStore = create(
  devtools(
    persist(
      (set, get) => ({
        user: null,
        token: null,
        loading: false,
        error: null,

        get isLoggedIn() {
          return !!get().token && !!get().user
        },

        login: async (username, password) => {
          set({ loading: true, error: null })

          try {
            const response = await fetch('/api/login', {
              method: 'POST',
              headers: { 'Content-Type': 'application/json' },
              body: JSON.stringify({ username, password })
            })

            const data = await response.json()

            set({
              user: data.user,
              token: data.token,
              loading: false
            })
          } catch (error) {
            set({ error: error.message, loading: false })
          }
        },

        logout: () => {
          set({ user: null, token: null })
        },

        updateUser: updates => {
          set(state => ({
            user: { ...state.user, ...updates }
          }))
        }
      }),
      {
        name: 'user-storage', // localStorage key
        partialize: state => ({ token: state.token }) // 只持久化 token
      }
    ),
    { name: 'UserStore' } // DevTools name
  )
)

// ==================== Cart Store ====================

const useCartStore = create(
  devtools(
    immer((set, get) => ({
      items: [],

      get totalItems() {
        return get().items.reduce((sum, item) => sum + item.quantity, 0)
      },

      get totalPrice() {
        return get().items.reduce(
          (sum, item) => sum + item.price * item.quantity,
          0
        )
      },

      addItem: product => {
        set(state => {
          const existingItem = state.items.find(item => item.id === product.id)

          if (existingItem) {
            existingItem.quantity += 1
          } else {
            state.items.push({ ...product, quantity: 1 })
          }
        })
      },

      removeItem: productId => {
        set(state => {
          state.items = state.items.filter(item => item.id !== productId)
        })
      },

      updateQuantity: (productId, quantity) => {
        set(state => {
          const item = state.items.find(item => item.id === productId)
          if (item) {
            if (quantity <= 0) {
              state.items = state.items.filter(i => i.id !== productId)
            } else {
              item.quantity = quantity
            }
          }
        })
      },

      clearCart: () => {
        set({ items: [] })
      }
    })),
    { name: 'CartStore' }
  )
)

// ==================== UI Store ====================

const useUIStore = create(set => ({
  theme: 'light',
  sidebarOpen: false,
  notifications: [],

  toggleTheme: () =>
    set(state => ({
      theme: state.theme === 'light' ? 'dark' : 'light'
    })),

  toggleSidebar: () =>
    set(state => ({
      sidebarOpen: !state.sidebarOpen
    })),

  addNotification: notification =>
    set(state => ({
      notifications: [
        ...state.notifications,
        { id: Date.now(), ...notification }
      ]
    })),

  removeNotification: id =>
    set(state => ({
      notifications: state.notifications.filter(n => n.id !== id)
    }))
}))

// ==================== Components ====================

function LoginButton() {
  const login = useUserStore(state => state.login)
  const loading = useUserStore(state => state.loading)

  const handleLogin = () => {
    login('demo', 'password')
  }

  return (
    <button onClick={handleLogin} disabled={loading}>
      {loading ? 'Logging in...' : 'Login'}
    </button>
  )
}

function UserGreeting() {
  const user = useUserStore(state => state.user)
  const logout = useUserStore(state => state.logout)

  if (!user) {
    return <LoginButton />
  }

  return (
    <div>
      <span>Welcome, {user.name}!</span>
      <button onClick={logout}>Logout</button>
    </div>
  )
}

function CartIcon() {
  const totalItems = useCartStore(state => state.totalItems)

  return <div>🛒 {totalItems}</div>
}

function Cart() {
  const items = useCartStore(state => state.items)
  const totalPrice = useCartStore(state => state.totalPrice)
  const addItem = useCartStore(state => state.addItem)
  const removeItem = useCartStore(state => state.removeItem)
  const clearCart = useCartStore(state => state.clearCart)

  const products = [
    { id: 1, name: 'Product A', price: 10 },
    { id: 2, name: 'Product B', price: 20 }
  ]

  return (
    <div>
      <h3>Cart</h3>

      {/* Products */}
      {products.map(product => (
        <button key={product.id} onClick={() => addItem(product)}>
          Add {product.name}
        </button>
      ))}

      {/* Cart Items */}
      {items.map(item => (
        <div key={item.id}>
          {item.name} x {item.quantity} = ${item.price * item.quantity}
          <button onClick={() => removeItem(item.id)}>Remove</button>
        </div>
      ))}

      <p>Total: ${totalPrice}</p>
      <button onClick={clearCart}>Clear Cart</button>
    </div>
  )
}

// ==================== App ====================

function App() {
  return (
    <div>
      <UserGreeting />
      <CartIcon />
      <Cart />
    </div>
  )
}

4.5 Zustand 中间件

jsx
import { create } from 'zustand'
import {
  persist, // 持久化
  devtools, // Redux DevTools 集成
  immer, // Immer 集成
  subscribeWithSelector, // 订阅特定状态变化
  combine // 合并多个 store
} from 'zustand/middleware'

// 1. persist - 持久化到 localStorage/sessionStorage
const usePersistedStore = create(
  persist(
    set => ({
      count: 0,
      increment: () => set(state => ({ count: state.count + 1 }))
    }),
    {
      name: 'my-storage', // unique name
      storage: localStorage, // or sessionStorage
      partialize: state => ({ count: state.count }) // 选择性持久化
    }
  )
)

// 2. devtools - Redux DevTools 支持
const useDevtoolsStore = create(
  devtools(
    set => ({
      count: 0,
      increment: () => set({ count: 1 }, false, 'increment') // action name
    }),
    { name: 'MyStore' }
  )
)

// 3. immer - 使用 Immer 进行不可变更新
const useImmerStore = create(
  immer(set => ({
    user: { name: 'John', age: 30 },
    updateAge: () =>
      set(state => {
        state.user.age += 1 // 直接修改
      })
  }))
)

// 4. subscribeWithSelector - 订阅特定状态变化
const useSubscribeStore = create(
  subscribeWithSelector((set, get) => ({
    count: 0,
    increment: () => set({ count: get().count + 1 })
  }))
)

// 在组件外部订阅
useSubscribeStore.subscribe(
  state => state.count, // selector
  count => {
    // callback
    console.log('Count changed:', count)
  }
)

// 5. 组合多个中间件
const useCombinedStore = create(
  devtools(
    persist(
      immer(set => ({
        count: 0,
        increment: () =>
          set(state => {
            state.count += 1
          })
      })),
      { name: 'combined-storage' }
    ),
    { name: 'CombinedStore' }
  )
)

4.6 高级用法

jsx
import { create, useStore } from 'zustand'
import { createContext, useContext } from 'react'

// ==================== 模式一:Context 模式(用于测试或多实例) ====================

const StoreContext = createContext(null)

const createStore = () =>
  create(set => ({
    count: 0,
    increment: () => set(state => ({ count: state.count + 1 }))
  }))

function StoreProvider({ children }) {
  const store = createStore()
  return <StoreContext.Provider value={store}>{children}</StoreContext.Provider>
}

function useBoundStore(selector) {
  const store = useContext(StoreContext)
  return useStore(store, selector)
}

// ==================== 模式二:Slice 模式(模块化) ====================

const createUserSlice = (set, get) => ({
  user: null,
  setUser: user => set({ user }),
  clearUser: () => set({ user: null })
})

const createCartSlice = (set, get) => ({
  items: [],
  addItem: item =>
    set(state => ({
      items: [...state.items, item]
    })),
  clearCart: () => set({ items: [] })
})

const useBoundStore = create((...a) => ({
  ...createUserSlice(...a),
  ...createCartSlice(...a)
}))

// ==================== 模式三:异步 Actions ====================

const useAsyncStore = create(set => ({
  data: null,
  loading: false,
  error: null,

  fetchData: async id => {
    set({ loading: true, error: null })

    try {
      const response = await fetch(`/api/data/${id}`)
      const data = await response.json()
      set({ data, loading: false })
    } catch (error) {
      set({ error: error.message, loading: false })
    }
  }
}))

// ==================== 模式四:Computed Values ====================

const useComputedStore = create((set, get) => ({
  items: [],

  // 计算属性需要在 selector 中实现
  addItem: item =>
    set(state => ({
      items: [...state.items, item]
    }))
}))

// 使用 selector 实现计算属性
const useTotalItems = () =>
  useComputedStore(state =>
    state.items.reduce((sum, item) => sum + item.quantity, 0)
  )

// 或者使用自定义 hook
const useCartTotals = () => {
  const items = useComputedStore(state => state.items)

  return {
    totalItems: items.reduce((sum, item) => sum + item.quantity, 0),
    totalPrice: items.reduce((sum, item) => sum + item.price * item.quantity, 0)
  }
}

4.7 使用场景

场景适用性
中小型应用✅ 非常适合
快速原型开发✅ 非常适合
需要简洁代码✅ 非常适合
需要持久化✅ 内置支持
需要多 store✅ 支持
超大型复杂应用⚠️ 需要良好组织

4.8 优缺点

优点:

  • 极简 API:学习成本低,上手快
  • 无 Provider:不需要包裹 Provider 组件
  • 体积小:仅约 1KB gzipped
  • TypeScript 友好:类型推断完善
  • 选择性订阅:精确控制组件渲染
  • 中间件支持:persist、devtools、immer 等
  • React 18 兼容:支持并发渲染

缺点:

  • 调试工具:需要配合 Redux DevTools
  • 时间旅行:不如 Redux 原生支持完善
  • 社区生态:相比 Redux,生态较小
  • 大型项目:需要自行组织代码结构

5. 方案对比总结

5.1 核心特性对比

特性useReducerReduxMobXZustand
学习曲线中高
样板代码
包体积0 (内置)~7KB~16KB~1KB
调试工具基础优秀良好良好
TypeScript
中间件
时间旅行⚠️⚠️
SSR 支持
React 18

5.2 适用场景对比

场景推荐方案原因
组件内部复杂状态useReducer无需额外依赖,逻辑集中
小型项目 (< 10 组件)Zustand / useReducer简单直接,无需复杂架构
中型项目 (10-50 组件)Zustand / MobX平衡简洁性和功能性
大型项目 (> 50 组件)Redux / MobX成熟的架构和工具链
团队协作Redux强制性的代码结构
快速原型Zustand / MobX样板代码少
需要严格状态追踪Redux单向数据流,可预测
面向对象偏好MobX类和装饰器风格
函数式偏好Redux / Zustand纯函数和不可变数据

5.3 性能对比

方案渲染优化方式性能特点
useReducerContext + useMemo需要手动优化,Context 可能导致不必要渲染
ReduxuseSelector选择性订阅,性能良好
MobXobserver + 自动追踪细粒度响应,自动优化
Zustandselector选择性订阅,性能优秀

5.4 选型建议

项目规模

    ├── 小型项目 (< 10 组件)
    │   └── useReducer + Context 或 Zustand

    ├── 中型项目 (10-50 组件)
    │   ├── 需要快速开发 → Zustand 或 MobX
    │   └── 需要规范架构 → Redux Toolkit

    └── 大型项目 (> 50 组件)
        ├── 团队经验丰富 → Redux Toolkit
        ├── OOP 风格偏好 → MobX
        └── 追求简洁 → Zustand

5.5 迁移建议

难度建议
useStateuseReducer适合状态逻辑变复杂时
useReducerRedux需要全局状态时
ReduxZustand简化代码,减少样板
MobXZustand函数式风格偏好
ReduxMobX需要重写状态逻辑

总结

选择状态管理方案时,应考虑以下因素:

  1. 项目规模:小型项目优先选择简单方案
  2. 团队经验:选择团队熟悉的方案
  3. 性能需求:考虑渲染优化和包体积
  4. 开发效率:平衡样板代码和开发速度
  5. 维护成本:考虑长期维护和扩展

没有绝对最好的方案,只有最适合当前项目需求的方案。建议在项目初期选择简单的方案,随着需求复杂度增加再考虑升级或迁移。

基于 VitePress 的本地知识库