Appearance
React 状态管理实践
状态管理是 React 应用开发中的核心问题。本文将介绍 React 中各种状态管理方案,从本地状态到全局状态,帮助你选择最适合的状态管理方案。
状态管理方案概览
React 应用中的状态管理可以分为几个层次:
- 本地状态:组件内部状态(useState、useReducer)
- 共享状态:组件间共享的状态(Context API、状态提升)
- 全局状态:应用级别的状态(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 的复杂功能
最佳实践
- 从简单开始:优先使用本地状态,只在必要时提升状态
- 合理拆分状态:避免将所有状态放在一个地方
- 使用自定义 Hooks:封装状态逻辑,提高复用性
- 性能优化:注意 Context 和全局状态导致的重新渲染
- 类型安全:使用 TypeScript 提供类型支持
总结
React 状态管理有多种方案,每种方案都有其适用场景。选择合适的状态管理方案需要考虑应用规模、团队经验、性能要求等因素。从简单的本地状态开始,随着应用复杂度增加,逐步引入更强大的状态管理方案。