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
获取 state
和 dispatch
:
// 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 嵌套问题 |
核心区别对比
对比维度 | 纯 localStorage | Context + 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 内置的状态管理方案,适合轻量级需求。- 对于更复杂的状态管理,可考虑 Zustand 或 Redux Toolkit。
- 如果涉及大量异步逻辑,建议结合 React Query 或 SWR 使用。
相关文章:
React状态管理Context API + useReducer
在 React 中,Context API useReducer 是一种轻量级的状态管理方案,适合中小型应用或需要跨组件共享复杂状态的场景。它避免了 Redux 的繁琐配置,同时提供了清晰的状态更新逻辑。 1. 基本使用步骤 (1) 定义 Reducer 类似于 Redux 的 reduce…...
【无标题】路径着色问题的革命性重构:拓扑色动力学模型下的超越与升华
路径着色问题的革命性重构:拓扑色动力学模型下的超越与升华 一、以色列路径着色模型的根本局限 mermaid graph TB A[以色列路径着色模型] --> B[强连通约束] A --> C[仅实边三角剖分] A --> D[静态色彩分配] B --> E[无法描述非相邻关系] C --> F[忽…...

Doris Catalog 联邦分析查询性能优化:从排查到优化的完整指南
在大数据分析中,Doris 的 Catalog 联邦分析功能为整合多源数据提供了有力支持。然而,在实际应用中,可能会遇到各种问题影响其正常运行。本文将详细剖析这些问题并提供解决方案。 一、联邦分析查询慢:内外表通用排查逻辑 当遇到 …...

01 Deep learning神经网络的编程基础 二分类--吴恩达
二分类 1. 核心定义 二分类任务是监督学习中最基础的问题类型,其目标是将样本划分为两个互斥类别。设样本特征空间为 X ⊆ R n \mathcal{X} \subseteq \mathbb{R}^n X⊆Rn,输出空间为 Y { 0 , 1 } \mathcal{Y} \{0,1\} Y{0,1},学习目标为…...

视频自动化分割方案:支持按时间与段数拆分
在日常视频处理任务中,如何快速将一个较长的视频文件按照指定规则拆分为多个片段,是许多用户都会遇到的问题。尤其对于需要批量处理视频的开发者、自媒体运营者或内容创作者来说,手动剪辑不仅效率低下,还容易出错。这是一款绿色免…...
Open SSL 3.0相关知识以及源码流程分析
Open SSL 3.0相关知识以及源码流程分析 编译 windows环境编译1、工具安装 安装安装perl脚本解释器、安装nasm汇编器(添加到环境变量)、Visual Studio编译工具 安装dmake ppm install dmake # 需要过墙2、开始编译 # 1、找到Visual Studio命令行编译工具目录 或者菜单栏直接…...

股指期货合约价值怎么算?
股指期货合约价值就是你买一手股指期货合约,理论上值多少钱。这个价值是根据期货的价格和合约乘数来计算的。就好比你买了一斤苹果,价格是5块钱一斤,那你买一斤就得付5块钱。股指期货也是一样,只不过它的计算稍微复杂一点点。 一…...

【QT】使用QT帮助手册找控件样式
选择帮助—》输入stylesheet(小写)—》选择stylesheet—》右侧选择Qt Style Sheets Reference 2.使用CtrlF—》输入要搜索的控件—》点击Customizing QScrollBar 3.显示参考样式表–》即可放入QT-designer的样式表中...

计算机网络(5)——数据链路层
1.概述 数据链路层负责一套链路上从一个节点向另一个物理链路直接相连的相邻节点传输数据报。换言之,主要解决相邻节点间的可靠数据传输 节点(nodes):路由器和主机 链路(links):连接相邻节点的通信信道 2.数据链路层服务 2.1 组帧 组帧(fra…...

VuePress完美整合Toast消息提示
VuePress 整合 Vue-Toastification 插件笔记 记录如何在 VuePress 项目中整合使用 vue-toastification 插件,实现优雅的消息提示。 一、安装依赖 npm install vue-toastification或者使用 yarn: yarn add vue-toastification二、配置 VuePress 客户端增…...
JVM 调优参数详解与实践
JVM 是 Java 程序性能的关键,合理的调优可以显著提升系统稳定性和吞吐量。本文将从基础参数出发,结合线上生产实践,对常用调优参数进行深入剖析与实战分享。 一、JVM内存结构概览 在进行JVM参数调优前,了解JVM内存结构非常关键 堆内存(Heap):用于存储对象,是GC主要处理…...

adb 连不上真机设备问题汇总
问题一、无法弹出 adb 调试授权弹窗 详细描述: 开发者选项中已打开 usb 调试,仅充电模式下 usb 调试也已打开,电脑通过 usb 连上手机后,一直弹出 adb 调试授权弹窗,尝试取消授权再次连接,还是无法弹出问题…...

[yolov11改进系列]基于yolov11引入注意力机制SENetV1或者SENetV2的python源码+训练源码
本文给大家带来的改进机制是SENet(Squeeze-and-Excitation Networks)其是一种通过调整卷积网络中的通道关系来提升性能的网络结构。SENet并不是一个独立的网络模型Q,而是一个可以和现有的任何一个模型相结合的模块(可以看作是一种…...

鸿蒙仓颉语言开发实战教程:商城搜索页
大家好,今天要分享的是仓颉语言商城应用的搜索页。 搜索页的内容比较多,都有点密集恐惧症了,不过我们可以从上至下将它拆分开来,逐一击破。 导航栏 搜索页的的最顶部是导航栏,由返回按钮和搜索框两部分组成,比较简单…...
上门服务小程序会员系统框架设计
逻辑分析 会员注册与登录:用户需要能够通过小程序进行会员注册,提供必要信息如手机号码、密码等,注册成功后可登录系统。会员信息管理:包括会员基本信息(姓名、联系方式等)的修改、查看,同时可能…...

图像去雾数据集总汇
自然去雾数据集 部分的数据清洗可以看这里:图像去雾数据集的下载和预处理操作 RESIDE-IN 将ITS作为训练集,SOTSindoor作为测试集。训练集13990对,验证集500对。 目前室内sota常用,最高已经卷到PSNR-42.72 最初应该是dehazefo…...
小程序引入deepseek
首先需要申请key: 地址 deepseek文档地址 使用wx.request获取数据 const task wx.request({url: https://api.deepseek.com/chat/completions,method: POST,responseType: text,headers: {Content-Type: application/json,Authorization: Bearer YOUR_API_KEY},dataType: te…...

网络攻防技术十四:入侵检测与网络欺骗
文章目录 一、入侵检测概述二、入侵系统的分类三、入侵检测的分析方法1、特征检测(滥用检测、误用检测)2、异常检测 四、Snort入侵检测系统五、网络欺诈技术1、蜜罐2、蜜网3、网络欺骗防御 六、简答题1. 入侵检测系统对防火墙的安全弥补作用主要体现在哪…...

C++笔记-C++11(一)
1.C11的发展历史 C11 是 C 的第⼆个主要版本,并且是从 C98 起的最重要更新。它引⼊了⼤量更改,标准化了既有实践,并改进了对 C 程序员可⽤的抽象。在它最终由 ISO 在 2011 年 8 ⽉ 12 ⽇采纳前,⼈们曾使⽤名称“C0x”,…...

JVM 类初始化和类加载 详解
类初始化和类加载 类加载的时机 加载、验证、准备、初始化和卸载这五个阶段的顺序是确定的,类型的加载过程必须按照这种顺序按部就班地开始,而解析阶段则不一定:它在某些情况下可以在初始化阶段之后再开始(懒解析)&am…...

B站缓存视频数据m4s转mp4
B站缓存视频数据m4s转mp4 结构分析 结构分析 在没有改变数据存储目录的情况下,b站默认数据保存目录为: Android->data->tv.danmaku.bili->download每个文件夹代表一个集合的视频,比如,我下载的”java从入门到精通“&…...

DeepSeek 助力 Vue3 开发:打造丝滑的日历(Calendar),日历_天气预报日历示例(CalendarView01_18)
前言:哈喽,大家好,今天给大家分享一篇文章!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏关注哦 💕 目录 Deep…...

【机器学习】主成分分析 (PCA)
目录 一、基本概念 二、数学推导 2.1 问题设定:寻炸最大方差的投影方向 2.2 数据中心化 2.3 目标函数:最大化投影后的方差 2.4 约束条件 2.5 拉格朗日乘子法 编辑 2.6 主成分提取 2.7 降维公式 三、SVD 四、实际案例分析 一、基本概念 主…...

二叉树-104.二叉树的最大深度-力扣(LeetCode)
一、题目解析 这里需要注意根节点的深度是1,也就是说计算深度的是从1开始计算的 二、算法原理 解法1:广度搜索,使用队列 解法2:深度搜索,使用递归 当计算出左子树的深度l,与右子树的深度r时,…...

物料转运人形机器人适合应用于那些行业?解锁千行百业的智慧物流革命
当传统物流设备困于固定轨道,当人力搬运遭遇效率与安全的天花板,物料转运人形机器人正以颠覆性姿态重塑产业边界。富唯智能凭借GRID大模型驱动的"感知-决策-执行"闭环系统,让物料流转从机械输送升级为智慧调度——这不仅是工具的革…...
k8s开发webhook使用certmanager生成证书
1.创建 Issuer apiVersion: cert-manager.io/v1 kind: Issuer metadata:name: selfsigned-issuernamespace: default spec:selfSigned: {}2.Certificate(自动生成 TLS 证书) apiVersion: cert-manager.io/v1 kind: Certificate metadata:name: webhook…...

时序预测模型测试总结
0.背景描述 公司最近需要在仿真平台上增加一些AI功能,针对于时序数据,想到的肯定是时序数据处理模型,典型的就两大类:LSTM 和 tranformer 。查阅文献,找到一篇中石化安全工程研究院有限公司的文章,题目为《…...

第四十五天打卡
知识点回顾: tensorboard的发展历史和原理 tensorboard的常见操作 tensorboard在cifar上的实战:MLP和CNN模型 效果展示如下,很适合拿去组会汇报撑页数: 作业:对resnet18在cifar10上采用微调策略下,用tensor…...

springboot mysql/mariadb迁移成oceanbase
前言:项目架构为 springbootmybatis-plusmysql 1.部署oceanbase服务 2.springboot项目引入oceanbase依赖(即ob驱动) ps:删除原有的mysql/mariadb依赖 <dependency> <groupId>com.oceanbase</groupId> …...

npm install 报错:npm error: ...node_modules\deasync npm error command failed
npm install 时报错如下: 首先尝试更换node版本,当前node版本20.15.0,更换node版本为16.17.0。再次执行npm install安装成功...