Skip to content

React 状态管理实践

状态管理是 React 应用开发中的核心问题。本文将介绍 React 中各种状态管理方案,从本地状态到全局状态,帮助你选择最适合的状态管理方案。

状态管理方案概览

React 应用中的状态管理可以分为几个层次:

  1. 本地状态:组件内部状态(useState、useReducer)
  2. 共享状态:组件间共享的状态(Context API、状态提升)
  3. 全局状态:应用级别的状态(Redux、Zustand、Jotai)

本地状态管理

useState

useState 是最基础的状态管理方式,适用于简单的组件状态。

javascript
import { useState } from 'react'

function Counter() {
  const [count, setCount] = useState(0)
  
  return (
    <div>
      <p>计数: {count}</p>
      <button onClick={() => setCount(count + 1)}>增加</button>
      <button onClick={() => setCount(count - 1)}>减少</button>
    </div>
  )
}

useReducer

useReducer 适用于复杂的状态逻辑,特别是当状态更新逻辑复杂时。

javascript
import { useReducer } from 'react'

const initialState = {
  todos: [],
  filter: 'all'
}

function todoReducer(state, action) {
  switch (action.type) {
    case 'ADD_TODO':
      return {
        ...state,
        todos: [...state.todos, {
          id: Date.now(),
          text: action.text,
          completed: false
        }]
      }
    case 'TOGGLE_TODO':
      return {
        ...state,
        todos: state.todos.map(todo =>
          todo.id === action.id
            ? { ...todo, completed: !todo.completed }
            : todo
        )
      }
    case 'SET_FILTER':
      return {
        ...state,
        filter: action.filter
      }
    default:
      return state
  }
}

function TodoApp() {
  const [state, dispatch] = useReducer(todoReducer, initialState)
  
  return (
    <div>
      <input
        onKeyPress={e => {
          if (e.key === 'Enter') {
            dispatch({ type: 'ADD_TODO', text: e.target.value })
            e.target.value = ''
          }
        }}
      />
      {state.todos.map(todo => (
        <div key={todo.id}>
          <input
            type="checkbox"
            checked={todo.completed}
            onChange={() => dispatch({ type: 'TOGGLE_TODO', id: todo.id })}
          />
          {todo.text}
        </div>
      ))}
    </div>
  )
}

Context API

Context API 是 React 内置的跨组件数据传递方案,适用于中等规模的状态共享。

基础用法

javascript
import { createContext, useContext, useState } from 'react'

const ThemeContext = createContext()

function ThemeProvider({ children }) {
  const [theme, setTheme] = useState('light')
  
  const toggleTheme = () => {
    setTheme(prev => prev === 'light' ? 'dark' : 'light')
  }
  
  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  )
}

function useTheme() {
  const context = useContext(ThemeContext)
  if (!context) {
    throw new Error('useTheme must be used within ThemeProvider')
  }
  return context
}

function App() {
  return (
    <ThemeProvider>
      <Header />
      <Main />
    </ThemeProvider>
  )
}

function Header() {
  const { theme, toggleTheme } = useTheme()
  
  return (
    <header className={theme}>
      <button onClick={toggleTheme}>切换主题</button>
    </header>
  )
}

性能优化

Context 可能导致不必要的重新渲染,需要合理拆分 Context。

javascript
// ❌ 不好:所有状态在一个 Context 中
const AppContext = createContext()

function AppProvider({ children }) {
  const [user, setUser] = useState(null)
  const [theme, setTheme] = useState('light')
  const [notifications, setNotifications] = useState([])
  
  // 任何一个状态变化,所有消费者都会重新渲染
  return (
    <AppContext.Provider value={{ user, theme, notifications }}>
      {children}
    </AppContext.Provider>
  )
}

// ✅ 好:按功能拆分 Context
const UserContext = createContext()
const ThemeContext = createContext()
const NotificationContext = createContext()

function UserProvider({ children }) {
  const [user, setUser] = useState(null)
  return (
    <UserContext.Provider value={{ user, setUser }}>
      {children}
    </UserContext.Provider>
  )
}

Redux

Redux 是最流行的全局状态管理库,适用于大型应用。

基础设置

javascript
// store.js
import { createStore } from 'redux'

const initialState = {
  count: 0
}

function counterReducer(state = initialState, action) {
  switch (action.type) {
    case 'INCREMENT':
      return { ...state, count: state.count + 1 }
    case 'DECREMENT':
      return { ...state, count: state.count - 1 }
    default:
      return state
  }
}

const store = createStore(counterReducer)
export default store

使用 Redux Toolkit(推荐)

Redux Toolkit 是 Redux 官方推荐的工具集,简化了 Redux 的使用。

javascript
// store.js
import { configureStore, 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 const store = configureStore({
  reducer: {
    counter: counterSlice.reducer
  }
})

// 组件中使用
import { useSelector, useDispatch } from 'react-redux'
import { increment, decrement } from './store'

function Counter() {
  const count = useSelector(state => state.counter.value)
  const dispatch = useDispatch()
  
  return (
    <div>
      <span>{count}</span>
      <button onClick={() => dispatch(increment())}>+</button>
      <button onClick={() => dispatch(decrement())}>-</button>
    </div>
  )
}

Zustand

Zustand 是一个轻量级的状态管理库,API 简洁,易于使用。

javascript
import create from 'zustand'

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>
      <span>{count}</span>
      <button onClick={increment}>+</button>
      <button onClick={decrement}>-</button>
    </div>
  )
}

Jotai

Jotai 是一个基于原子化状态的状态管理库,采用自底向上的方法。

javascript
import { atom, useAtom } from 'jotai'

const countAtom = atom(0)

function Counter() {
  const [count, setCount] = useAtom(countAtom)
  
  return (
    <div>
      <span>{count}</span>
      <button onClick={() => setCount(count + 1)}>+</button>
      <button onClick={() => setCount(count - 1)}>-</button>
    </div>
  )
}

// 派生状态
const doubleCountAtom = atom((get) => get(countAtom) * 2)

状态管理选择指南

何时使用本地状态(useState/useReducer)

  • 状态只在单个组件内使用
  • 状态逻辑简单
  • 不需要跨组件共享

何时使用 Context API

  • 需要在多个组件间共享状态
  • 状态规模中等
  • 不需要复杂的状态管理功能

何时使用 Redux

  • 大型应用
  • 需要时间旅行调试
  • 需要中间件支持(如异步操作)
  • 团队熟悉 Redux 生态

何时使用 Zustand/Jotai

  • 需要轻量级解决方案
  • 希望 API 简洁
  • 不需要 Redux 的复杂功能

最佳实践

  1. 从简单开始:优先使用本地状态,只在必要时提升状态
  2. 合理拆分状态:避免将所有状态放在一个地方
  3. 使用自定义 Hooks:封装状态逻辑,提高复用性
  4. 性能优化:注意 Context 和全局状态导致的重新渲染
  5. 类型安全:使用 TypeScript 提供类型支持

总结

React 状态管理有多种方案,每种方案都有其适用场景。选择合适的状态管理方案需要考虑应用规模、团队经验、性能要求等因素。从简单的本地状态开始,随着应用复杂度增加,逐步引入更强大的状态管理方案。


辛田信息技术 · 内部技术分享 · 仅供学习与参考