当前位置: 首页 > article >正文

React状态管理Context API + useReducer

在 React 中,Context API + useReducer 是一种轻量级的状态管理方案,适合中小型应用或需要跨组件共享复杂状态的场景。它避免了 Redux 的繁琐配置,同时提供了清晰的状态更新逻辑。


1. 基本使用步骤

(1) 定义 Reducer

类似于 Redux 的 reducer,用于处理状态更新逻辑:

// reducer.js
export const initialState = {count: 0,user: null,
};export function reducer(state, action) {switch (action.type) {case 'INCREMENT':return { ...state, count: state.count + 1 };case 'DECREMENT':return { ...state, count: state.count - 1 };case 'SET_USER':return { ...state, user: action.payload };default:return state;}
}

(2) 创建 Context 和 Provider

使用 createContext 创建 Context,并用 useReducer 管理状态:

// AppContext.js
import { createContext, useReducer } from 'react';
import { initialState, reducer } from './reducer';// 1. 创建 Context
export const AppContext = createContext();// 2. 创建 Provider 组件
export function AppProvider({ children }) {const [state, dispatch] = useReducer(reducer, initialState);return (<AppContext.Provider value={{ state, dispatch }}>{children}</AppContext.Provider>);
}

(3) 在顶层组件包裹 Provider

// App.js
import { AppProvider } from './AppContext';
import Counter from './Counter';function App() {return (<AppProvider><Counter /></AppProvider>);
}

(4) 在子组件使用状态

通过 useContext 获取 statedispatch

// Counter.js
import { useContext } from 'react';
import { AppContext } from './AppContext';export function Counter() {const { state, dispatch } = useContext(AppContext);return (<div><p>Count: {state.count}</p><button onClick={() => dispatch({ type: 'INCREMENT' })}>+</button><button onClick={() => dispatch({ type: 'DECREMENT' })}>-</button></div>);
}

2. 数据持久化

Context + useReducer 管理的状态是纯内存状态,当页面刷新时,这些数据会丢失,因为 JavaScript 的内存会被清空,恢复到初始状态。
在 React 的 Context + useReducer 架构中实现数据持久化( localStorage sessionStorage,页面刷新不丢失)

2.1实现步骤

(1)定义 Reducer(持久化/非持久化/临时数据)
// reducer.js
export const initialState = {// 需要持久化的数据persistedData: { language: 'en' },// 非持久化数据sessionData: { loginForm: null },// 临时数据tempData: {count: 0}
};export function reducer(state, action) {switch (action.type) {// 持久化数据case 'SET_LANGUAGE':return { ...state, persistedData: { ...state.persistedData, language: action.payload } };// 非持久化数据case 'SET_LOGIN_FORM':return { ...state, sessionData: { ...state.sessionData, loginForm: action.payload } };// 临时数据case 'SET_COUNT':return {...state, tempData: { ...state.tempData, count: action.payload } }default:return state;}
}
(2)带持久化的Provider组件实现
// AppContext.jsx
import { createContext, useReducer, useEffect } from 'react';
import { initialState, reducer } from './reducer';// 1. 创建 Context
export const AppContext = createContext();// 2. 创建 Provider 组件
export function AppProvider({ children }) {const [state, dispatch] = useReducer(reducer,{...initialState,persistedData: JSON.parse(localStorage.getItem('persistedData')) || initialState.persistedData,sessionData: JSON.parse(sessionStorage.getItem('sessionData')) || initialState.sessionData});// 监听localStorage字段的变化useEffect(() => {localStorage.setItem('persistedData', JSON.stringify(state.persistedData));}, [state.persistedData]);// 监听sessionStorage 字段的变化useEffect(() => {sessionStorage.setItem('sessionData', JSON.stringify(state.sessionData));}, [state.sessionData]);return (<AppContext.Provider value={{ state, dispatch }}>{children}</AppContext.Provider>);
}
(3)在顶层组件包裹 Provider
// app.jsx
import { RouterProvider } from "react-router";
import router from "./router/index.jsx";
import { AppProvider } from '@stores/AppContext.jsx';
function App() {return (<AppProvider><div className="app"><RouterProvider router={router} /></div></AppProvider>)
}export default App

2.2 纯 localStorage 与 Context + useReducer + localStorage对比

1、 纯 localStorage特点

优点缺点
1. 实现简单,无需额外库1. 状态不同步:多个组件无法实时共享同一份数据
2. 适合极简场景2. 重复代码:每个组件需单独处理存储逻辑
3. 无性能开销(仅读写存储)3. 难以维护:业务复杂时逻辑分散

2、 Context + useReducer + localStorage特点

优点缺点
1. 状态全局共享:所有组件实时响应变化1. 代码量稍多(需设置 Context/Reducer)
2. 逻辑集中:易于维护和扩展2. 小型项目可能过度设计
3. 自动持久化:状态变更自动同步到存储3. 需处理 Provider 嵌套问题

核心区别对比

对比维度纯 localStorageContext + useReducer + localStorage
状态同步需手动触发,组件间不同步自动同步,全局状态一致
代码组织逻辑分散在各组件集中管理,高内聚低耦合
维护性难扩展,易出现重复代码易于扩展和维护
性能直接操作存储,无额外开销有 Context 的渲染开销(可通过 memo 优化)
适用场景简单页面、独立组件中大型应用、需共享状态的场景

总结

  • 直接 localStorage:简单粗暴,适合局部状态。
  • Context + useReducer + localStorage:专业方案,适合全局状态。

2.3注意事项

  • localStorage /sessionStorage只能存字符串,复杂数据需用 JSON.stringify
  • 优点:1、代码简洁,适合小型应用;2、无需第三方库;
  • 缺点: 1、 localStorage/sessionStorage是同步操作,可能阻塞主线程;2、存储大小有限(通常 5MB);

2. 进阶优化

(1) 封装自定义 Hook

避免在每个组件里重复写 useContext

// hooks/useAppContext.js
import { useContext } from 'react';
import { AppContext } from '../AppContext';export function useAppContext() {return useContext(AppContext);
}

然后在组件中使用:

const { state, dispatch } = useAppContext();

(2) 优化性能(避免不必要的渲染)

默认情况下,Context 的更新会导致所有消费者组件重新渲染。可以使用 memo + 拆分 Context 优化:

// 拆分多个 Context
const CountContext = createContext();
const UserContext = createContext();// 在 Provider 里分别提供
<CountContext.Provider value={{ countState, countDispatch }}><UserContext.Provider value={{ userState, userDispatch }}>{children}</UserContext.Provider>
</CountContext.Provider>

(3) 结合异步操作

可以在 dispatch 里处理异步逻辑(如 API 请求):

async function fetchUser(dispatch) {try {const user = await fetch('/api/user').then(res => res.json());dispatch({ type: 'SET_USER', payload: user });} catch (error) {dispatch({ type: 'SET_ERROR', payload: error.message });}
}// 在组件中调用
fetchUser(dispatch);

3. 优缺点对比

优点缺点
无需额外库,React 原生支持大型应用可能性能较差(需手动优化)
比 Redux 更轻量异步处理较麻烦(需手动封装)
适合中小型应用调试不如 Redux 方便(无 DevTools)

4. 适用场景

  • 小型/中型应用:不想引入 Redux 或 Zustand 时。
  • 组件层级较深:需要跨多层传递状态时。
  • 简单全局状态:如主题、用户登录信息等。

总结

  • Context + useReducer 是 React 内置的状态管理方案,适合轻量级需求。
  • 对于更复杂的状态管理,可考虑 ZustandRedux Toolkit
  • 如果涉及大量异步逻辑,建议结合 React QuerySWR 使用。
http://www.lryc.cn/news/2401600.html

相关文章:

  • 【无标题】路径着色问题的革命性重构:拓扑色动力学模型下的超越与升华
  • Doris Catalog 联邦分析查询性能优化:从排查到优化的完整指南
  • 01 Deep learning神经网络的编程基础 二分类--吴恩达
  • 视频自动化分割方案:支持按时间与段数拆分
  • Open SSL 3.0相关知识以及源码流程分析
  • 股指期货合约价值怎么算?
  • 【QT】使用QT帮助手册找控件样式
  • 计算机网络(5)——数据链路层
  • VuePress完美整合Toast消息提示
  • JVM 调优参数详解与实践
  • adb 连不上真机设备问题汇总
  • [yolov11改进系列]基于yolov11引入注意力机制SENetV1或者SENetV2的python源码+训练源码
  • 鸿蒙仓颉语言开发实战教程:商城搜索页
  • 上门服务小程序会员系统框架设计
  • 图像去雾数据集总汇
  • 小程序引入deepseek
  • 网络攻防技术十四:入侵检测与网络欺骗
  • C++笔记-C++11(一)
  • JVM 类初始化和类加载 详解
  • B站缓存视频数据m4s转mp4
  • DeepSeek 助力 Vue3 开发:打造丝滑的日历(Calendar),日历_天气预报日历示例(CalendarView01_18)
  • 【机器学习】主成分分析 (PCA)
  • 二叉树-104.二叉树的最大深度-力扣(LeetCode)
  • 物料转运人形机器人适合应用于那些行业?解锁千行百业的智慧物流革命
  • k8s开发webhook使用certmanager生成证书
  • 时序预测模型测试总结
  • 第四十五天打卡
  • springboot mysql/mariadb迁移成oceanbase
  • npm install 报错:npm error: ...node_modules\deasync npm error command failed
  • Filebeat收集nginx日志到elasticsearch,最终在kibana做展示(二)