
随着 React 应用复杂化,"状态该放在哪、怎么管理"成为团队争论的焦点。常见的困惑包括:
useState 是否够用?其实不同的状态管理方案各有适用场景,没有绝对的最好,只有最合适。下面拆解三种主流方案。
对于组件自己私有的、不跨层共享的状态,优先用 useState。当状态更新逻辑复杂(多个字段联动、依赖前一个值)时,用 useReducer 把更新逻辑集中到 reducer 中。
import { useState, useReducer } from"react";// useReducer:把复杂的状态更新逻辑收敛到 reducerconst initialState = { count: 0, step: 1 };functionreducer(state, action) {switch (action.type) {case"increment":return { ...state, count: state.count + state.step };case"decrement":return { ...state, count: state.count - state.step };case"setStep":return { ...state, step: action.payload };default:return state; }}exportdefaultfunctionCounter() {// useState 适合简单场景const [name, setName] = useState("张三");// useReducer 适合逻辑复杂的场景const [state, dispatch] = useReducer(reducer, initialState);return (<div><inputvalue={name}onChange={(e) => setName(e.target.value)} /><p> {state.count},步长 {state.step}</p><buttononClick={() => dispatch({ type: "increment" })}>+</button><buttononClick={() => dispatch({ type: "decrement" })}>-</button><buttononClick={() => dispatch({ type: "setStep", payload: 5 })}> 步长改为 5</button></div> );}原理:useState 提供简单的读写接口;useReducer 通过 dispatch 触发 action、reducer 纯函数计算新状态,逻辑清晰、可测试。
优缺点:零依赖、天然符合 React 哲学。缺点是无法跨组件共享,状态提升后会频繁传递 props。
当多个组件需要共享同一份数据(如主题、用户、语言),又不希望层层透传 props 时,用 Context。
import { createContext, useContext, useState } from"react";constThemeContext = createContext();// 提供方:包裹需要共享状态的子树exportfunctionThemeProvider({ children }) {const [theme, setTheme] = useState("light");return (<ThemeContext.Providervalue={{theme, setTheme }}> {children}</ThemeContext.Provider> );}// 消费方:任意深度的组件都能拿到 theme 和 setThemefunctionButton() {const { theme, setTheme } = useContext(ThemeContext);return (<buttononClick={() => setTheme(theme === "light" ? "dark" : "light")} style={{ background: theme === "dark" ? "#333" : "#fff" }} > 当前主题:{theme}</button> );}exportdefaultfunctionApp() {return (<ThemeProvider><Button /></ThemeProvider> );}原理:Context.Provider 提供值,useContext 在任意后代组件中订阅。当 value 变化时,所有消费该 Context 的组件都会重渲染。
优缺点:无需额外依赖、适合低频全局数据(主题、语言)。缺点是 value 变化会导致所有消费者重渲染,性能敏感场景需拆分成多个 Context 或配合 memo。
当应用状态复杂、跨模块共享、需要时间旅行调试、或团队需要统一规范时,引入全局状态管理库。这里以轻量的 Zustand 为例(Redux 与之类似但样板代码更多)。
import { create } from"zustand";// 创建 store:集中定义 state 与 actionconst useCartStore = create((set) => ({items: [],addItem: (product) =>set((state) => ({ items: [...state.items, product] })),removeItem: (id) =>set((state) => ({ items: state.items.filter((i) => i.id !== id) })),clear: () =>set({ items: [] }),}));functionCart() {const items = useCartStore((s) => s.items);const addItem = useCartStore((s) => s.addItem);const clear = useCartStore((s) => s.clear);return (<div><h3>购物车({items.length} 件)</h3><buttononClick={() => addItem({ id: Date.now(), name: "商品" })}> 添加</button><buttononClick={clear}>清空</button><ul> {items.map((i) => (<likey={i.id}>{i.name}</li> ))}</ul></div> );}exportdefaultfunctionApp() {return<Cart />;}原理:Zustand/Redux 把状态提升到组件树之外的单一 store,任意组件通过 hook 或 connect 订阅,天然支持跨组件、跨模块共享,配合 DevTools 可追踪每次状态变化。
优缺点:能力强、可扩展、可调试。缺点是引入额外依赖与学习成本,对简单项目属于过度设计。
总结:选择原则是"由小到大"。能用 useState 就不用 Context,能用 Context 就不用全局状态库。只有在状态确实复杂、跨模块共享频繁、需要调试追踪时才上 Redux/Zustand。避免为了一两个共享变量就引入重型状态库。
更多详细内容,请微信搜索"前端爱好者", 戳我 查看 。