createContext+useContext+useReducer组合管理React复杂状态

createContextuseContextuseReducer 的组合是 React 中管理全局状态的一种常见模式。这种模式非常适合在不引入第三方状态管理库(如 Redux)的情况下,管理复杂的全局状态。

以下是一个经典的例子,展示如何使用 createContextuseContextuseReducer 来实现一个简单的全局状态管理。

示例:Todo 应用

我们将实现一个简单的 Todo 应用,支持以下功能:

  1. 添加任务
  2. 删除任务
  3. 切换任务完成状态

1. 定义全局状态和操作

TodoContext.tsx

import React, { createContext, useReducer, useContext, ReactNode } from 'react';// 定义 Todo 项的类型
interface Todo {id: number;text: string;completed: boolean;
}// 定义全局状态的类型
interface TodoState {todos: Todo[];
}// 定义操作类型
type TodoAction =| { type: 'ADD_TODO'; payload: string }| { type: 'TOGGLE_TODO'; payload: number }| { type: 'DELETE_TODO'; payload: number };// 定义初始状态
const initialState: TodoState = {todos: [],
};// 定义 reducer 函数
const todoReducer = (state: TodoState, action: TodoAction): TodoState => {switch (action.type) {case 'ADD_TODO':return {...state,todos: [...state.todos,{ id: Date.now(), text: action.payload, completed: false },],};case 'TOGGLE_TODO':return {...state,todos: state.todos.map((todo) =>todo.id === action.payload? { ...todo, completed: !todo.completed }: todo),};case 'DELETE_TODO':return {...state,todos: state.todos.filter((todo) => todo.id !== action.payload),};default:return state;}
};// 创建 Context
const TodoContext = createContext<{state: TodoState;dispatch: React.Dispatch<TodoAction>;
} | null>(null);// 创建 Provider 组件
export const TodoProvider = ({ children }: { children: ReactNode }) => {const [state, dispatch] = useReducer(todoReducer, initialState);return (<TodoContext.Provider value={{ state, dispatch }}>{children}</TodoContext.Provider>);
};// 自定义 Hook,用于使用 TodoContext
export const useTodoContext = () => {const context = useContext(TodoContext);if (!context) {throw new Error('useTodoContext must be used within a TodoProvider');}return context;
};

2. 使用全局状态

App.tsx

import React, { useState } from 'react';
import { TodoProvider, useTodoContext } from './TodoContext';const TodoList = () => {const { state, dispatch } = useTodoContext();return (<div><h2>Todo List</h2><ul>{state.todos.map((todo) => (<li key={todo.id}><spanstyle={{textDecoration: todo.completed ? 'line-through' : 'none',cursor: 'pointer',}}onClick={() => dispatch({ type: 'TOGGLE_TODO', payload: todo.id })}>{todo.text}</span><button onClick={() => dispatch({ type: 'DELETE_TODO', payload: todo.id })}>Delete</button></li>))}</ul></div>);
};const AddTodo = () => {const { dispatch } = useTodoContext();const [text, setText] = useState('');const handleAddTodo = () => {if (text.trim()) {dispatch({ type: 'ADD_TODO', payload: text });setText('');}};return (<div><inputtype="text"value={text}onChange={(e) => setText(e.target.value)}placeholder="Add a new task"/><button onClick={handleAddTodo}>Add</button></div>);
};const App = () => {return (<TodoProvider><h1>Todo App</h1><AddTodo /><TodoList /></TodoProvider>);
};export default App;

3. 代码解释

  1. TodoContext:
    • 使用 createContext 创建一个全局状态的上下文。
    • 使用 useReducer 管理全局状态和操作。
  2. TodoProvider:
    • 包裹应用的根组件,提供全局状态和 dispatch 方法。
  3. useTodoContext:
    • 自定义 Hook,用于简化 useContext 的使用,并确保上下文只能在 TodoProvider 内部使用。
  4. todoReducer:
    • 定义了如何根据不同的操作(ADD_TODO、TOGGLE_TODO、DELETE_TODO)更新全局状态。
  5. 组件分离:
    • AddTodo 组件负责添加任务。
    • TodoList 组件负责显示任务列表,并支持切换任务状态和删除任务。

4. 优势

  • 清晰的状态管理
    • 使用 useReducer 将状态更新逻辑集中在一个地方,便于维护和扩展。
  • 全局状态共享
    • 使用 createContext 和 useContext 实现全局状态共享,无需手动传递 props。
  • 组件解耦
    • 通过上下文和 dispatch,各组件可以独立处理自己的逻辑,而无需直接依赖其他组件。

5. 总结

createContext + useContext + useReducer 是一种轻量级的全局状态管理方案,适合中小型项目。它的核心思想是:

  1. 使用 createContext 提供全局状态。
  2. 使用 useReducer 管理状态更新逻辑。
  3. 使用 useContext 在组件中访问和操作全局状态。

这种模式简单易用,且不需要引入额外的状态管理库,非常适合 React 项目中需要共享状态的场景。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/74966.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

记一次常规的网络安全渗透测试

目录&#xff1a; 前言 互联网突破 第一层内网 第二层内网 总结 前言 上个月根据领导安排&#xff0c;需要到本市一家电视台进行网络安全评估测试。通过对内外网进行渗透测试&#xff0c;网络和安全设备的使用和部署情况&#xff0c;以及网络安全规章流程出具安全评估报告。本…

el-table,新增、复制数据后,之前的勾选状态丢失

需要考虑是否为 更新数据的方式不对 如果新增数据的方式是直接替换原数据数组&#xff0c;而不是通过正确的响应式数据更新方式&#xff08;如使用 Vue 的 this.$set 等方法 &#xff09;&#xff0c;也可能导致勾选状态丢失。 因为 Vue 依赖数据的响应式变化来准确更新视图和…

第15届蓝桥杯java-c组省赛真题

目录 一.拼正方形 1.题目 2.思路 3.代码 二.劲舞团 1.题目 2.思路 3.代码 三.数组诗意 1.题目 2.思路 3.代码 四.封闭图形个数 1.题目 2.思路 3.代码 五.吊坠 1.题目 六.商品库存管理 1.题目 2.思路 3.代码 七.挖矿 1.题目 2.思路 3.代码 八.回文字…

玄机-应急响应-入侵排查

靶机排查目标&#xff1a; 1.web目录存在木马&#xff0c;请找到木马的密码提交 查看/var/www/html。 使用find命令查找 find ./ -type f -name "*.php | xargs grep "eval("查看到1.php里面存在无条件一句话木马。 2.服务器疑似存在不死马&#xff0c;请找…

usbip学习记录

USB/IP: USB device sharing over IP make menuconfig配置&#xff1a; Device Drivers -> Staging drivers -> USB/IP support Device Drivers -> Staging drivers -> USB/IP support -> Host driver 如果还有作为客户端的需要&#xff0c;继续做以下配置&a…

爱普生高精度车规晶振助力激光雷达自动驾驶

在自动驾驶技术快速落地的今天&#xff0c;激光雷达作为车辆的“智慧之眼”&#xff0c;其测距精度与可靠性直接决定了自动驾驶系统的安全上限。而在这双“眼睛”的核心&#xff0c;爱普生&#xff08;EPSON&#xff09;的高精度车规晶振以卓越性能成为激光雷达实现毫米级感知的…

28--当路由器开始“宫斗“:设备控制面安全配置全解

当路由器开始"宫斗"&#xff1a;设备控制面安全配置全解 引言&#xff1a;路由器的"大脑保卫战" 如果把网络世界比作一座繁忙的城市&#xff0c;那么路由器就是路口执勤的交通警察。而控制面&#xff08;Control Plane&#xff09;就是警察的大脑&#xf…

58.基于springboot老人心理健康管理系统

目录 1.系统的受众说明 2.相关技术 2.1 B/S结构 2.2 MySQL数据库 3.系统分析 3.1可行性分析 3.1.1时间可行性 3.1.2 经济可行性 3.1.3 操作可行性 3.1.4 技术可行性 3.1.5 法律可行性 3.2系统流程分析 3.3系统功能需求分析 3.4 系统非功能需求分析 4.系统设计 …

去中心化固定利率协议

核心机制与分类 协议类型&#xff1a; 借贷协议&#xff08;如Yield、Notional&#xff09;&#xff1a;通过零息债券模型&#xff08;如fyDai、fCash&#xff09;锁定固定利率。 收益聚合器&#xff08;如Saffron、BarnBridge&#xff09;&#xff1a;通过风险分级或博弈论…

反射率均值与RCS均值的计算方法差异

1. 反射率均值&#xff08;Mean Reflectance&#xff09; 定义&#xff1a; 反射率是物体表面反射的电磁波能量与入射能量的“比例”&#xff0c;通常以百分比或小数表示。 反射率均值是对多个测量点反射率的算术平均&#xff0c;反映目标区域整体的平均反射特性。 特点&a…

[MySQL初阶]MySQL(8)索引机制:下

标题&#xff1a;[MySQL初阶]MySQL&#xff08;8&#xff09;索引机制&#xff1a;下 水墨不写bug 文章目录 四、从问题到底层&#xff0c;从现象到本质1.为什么插入的数据默认排好序2.MySQL的Page&#xff08;1&#xff09;为什么选择用Page&#xff1f;&#xff08;2&#x…

Access:在移动互联网与AI时代焕发新生

Microsoft Access&#xff1a;在移动互联网与AI时代焕发新生 在移动互联网和人工智能&#xff08;AI&#xff09;技术快速发展的今天&#xff0c;许多传统工具被认为已经过时。然而&#xff0c;Microsoft Access&#xff0c;这款曾经风靡一时的数据库&#xff0c;真的已经被淘…

【无人机】无人机PX4飞控系统高级软件架构

目录 1、概述&#xff08;图解&#xff09; 一、数据存储层&#xff08;Storage&#xff09; 二、外部通信层&#xff08;External Connectivity&#xff09; 三、核心通信枢纽&#xff08;Message Bus&#xff09; 四、硬件驱动层&#xff08;Drivers&#xff09; 五、飞…

【项目日记】高并发服务器项目总结

生活总是让我们遍体鳞伤&#xff0c; 但到后来&#xff0c; 那些受伤的地方一定会变成我们最强壮的地方。 -- 《老人与海》-- 高并发服务器项目总结 模块关系图项目工具模块缓冲区模块通用类型模块套接字socket模块信道Channel模块多路转接Poller模块 Reactor模块时间轮Tim…

Vue项目 bug 解决

Vue2项目部署失败 从gitee 上拉下一个前端项目&#xff0c;然后npm install&#xff0c;报错如下&#xff1a; 解决办法&#xff1a; 从 npm切换到cnpm&#xff1a;npm install -g cnpm执行命令export NODE_OPTIONS--openssl-legacy-provider下载依赖&#xff1a;cnpm instal…

接口自动化入门(四)

1. JMeter 的多组数据测试 1.1 使用 CSV 数据文件 JMeter 支持通过 CSV 文件提供多组测试数据&#xff0c;适用于参数化测试场景。具体步骤如下&#xff1a; 创建一个 CSV 文件&#xff0c;将测试数据以逗号分隔的形式存储。例如&#xff1a; username,passworduser1,pass1u…

企业数据分析何时该放弃Excel?

在企业数据分析中,Excel 的适用数据量范围取决于 数据复杂度、计算需求 和 硬件性能: 一、Excel 适合处理的数据量范围 数据规模适用场景限制与风险≤10万行- 日常报表 - 简单数据透视表 - 基础公式计算(如SUMIFS、VLOOKUP)处理流畅,无明显性能问题10万~50万行- 较复杂分析…

群晖NAS的最好的下载方式(虚拟机安装win系统安装下载软件)

一、背景 买NAS的其中一个用途就是下载&#xff0c;尤其是那种BT、磁力下载这种需要耗时较久的&#xff0c;开着电脑就是为了下载这种非常耗电和耗硬盘。 二、应对策略 既然有上面 “背景” 提到的痛点&#xff0c;有什么解决方式&#xff1f; NAS 上用docker安装迅雷&…

Spring AI与阿里云开发实践——生成式Java AI应用架构全解析

本文深度解析基于Spring框架与阿里云服务构建生成式AI应用的技术路径&#xff0c;涵盖架构设计、模型集成、性能优化三大维度。通过某金融企业智能客服系统实战案例&#xff0c;揭示Java生态下AI应用开发的7个关键实践要点&#xff0c;结合Gartner最新技术成熟度曲线&#xff0…

基于springboot体育俱乐部预约管理系统(源码+lw+部署文档+讲解),源码可白嫖!

摘要 随着我国经济的高速发展与人们生活水平的日益提高&#xff0c;人们对生活质量的追求也多种多样。尤其在人们生活节奏不断加快的当下&#xff0c;人们更趋向于足不出户解决生活上的问题&#xff0c;线上管理系统展现了其蓬勃生命力和广阔的前景。与此同时&#xff0c;在科…