react18中实现简易增删改查useReducer搭配useContext的高级用法

useReduceruseContext前面有单独介绍过,上手不难,现在我们把这两个api结合起来使用,该怎么用?还是结合之前的简易增删改查的demo,熟悉vue的应该可以看出,useReducer类似于vuexuseContext类似于vue中的injectprovided,来分析下思路。

实现效果请添加图片描述

代码实现

  • 文件拆解
    在这里插入图片描述
  • 组件入口文件 -> index.js
import { TasksContext, TasksDispatchContext } from "./context";
import { useReducer } from "react";
import { initialTasks } from "./taskLists";
import { taskReucers } from "./tasksReducer";
import AddTask from "./AddTask";
import TaskList from "./TaskList";
function State() {const [tasks, dispatch] = useReducer(taskReucers, initialTasks);return (<TasksContext.Provider value={tasks}><TasksDispatchContext.Provider value={dispatch}><AddTask /><TaskList /></TasksDispatchContext.Provider></TasksContext.Provider>);
}export default State;
  • AddTask.js
import { useState, useContext } from "react";
import { TasksDispatchContext } from "./context";
let nextId = 3;function AddTask() {let [msg, setMsg] = useState("");const dispatch = useContext(TasksDispatchContext);const handleSubmit = () => {if (!msg) return;setMsg("");dispatch({type: "added",task: {id: nextId++,text: msg,done: false,},});};const handleChange = (e) => {setMsg(e.target.value);};return (<><input type="text" value={msg} onChange={handleChange} /><button onClick={handleSubmit}>添加</button></>);
}export default AddTask;
  • context.js文件
import { createContext } from "react";export const TasksContext = createContext(null);
export const TasksDispatchContext = createContext(null);
  • taskReucers.js
export function taskReucers(state = [], action) {switch (action.type) {case "added":return [...state, action.task];case "changed":return state.map((task) => {if (task.id === action.task.id) {return action.task;} else return task;});case "deleted":return state.filter((task) => task.id !== action.task.id);default:throw new Error("Action type not found");}
}
  • taskListsData.js
export const initialTasks = [{ id: 0, text: "Philosopher’s Path", done: true },{ id: 1, text: "Visit the temple", done: false },{ id: 2, text: "Drink matcha", done: false },
];
  • TaskList.js
import { useState, useContext } from "react";
import Task from "./Task";
import { TasksContext } from "./context";function TaskList() {const [isEdit, setIsEdit] = useState(false);const tasks = useContext(TasksContext);const handleChangeValue = (value) => {};return (<ul>{tasks.map((task) => {return <Task key={task.id} task={task} />;})}</ul>);
}export default TaskList;
  • Task.js
import { useState, useContext } from "react";
import { TasksDispatchContext } from "./context";
function Task({ task }) {const [isEdit, setIsEdit] = useState(false);const dispatch = useContext(TasksDispatchContext);let todoContent = "";function handleChangeText(e) {dispatch({ type: "changed", task: { id: task.id, text: e.target.value } });}function handleDeleteTask(id) {dispatch({ type: "deleted", task: { id } });}if (isEdit) {todoContent = (<span><input type="text" value={task.text} onChange={handleChangeText} /><button onClick={() => setIsEdit(false)}>完成</button></span>);} else {todoContent = (<span><span>{task.text}</span><button onClick={() => setIsEdit(true)}>编辑</button></span>);}return (<li>{todoContent}<button onClick={() => handleDeleteTask(task.id)}>删除</button></li>);
}export default Task;

这样拆解后,明显的业务更加清晰,容易维护了,给后续接手的人一目了然的理解思路。
没有了组件层级之间的繁琐的层层传递数据和方法,代码结构也很清晰了。


进一步的优化业务代码

  • context.js的封装
import { createContext, useReducer } from "react";
import { initialTasks } from "./taskListsData";
import { taskReucers } from "./tasksReducer";export const TasksContext = createContext(null);
export const TasksDispatchContext = createContext(null);export default function TasksProvider({ children }) {const [tasks, dispatch] = useReducer(taskReucers, initialTasks);return (<TasksContext.Provider value={tasks}><TasksDispatchContext.Provider value={dispatch}>{children}</TasksDispatchContext.Provider></TasksContext.Provider>);
}
  • 入口文件index.js的优化
import AddTask from "./AddTask";
import TaskList from "./TaskList";
import TasksProvider from "./context";
function State() {return (<TasksProvider><AddTask /><TaskList /></TasksProvider>);
}export default State;

这样实现了同样的效果,代码更加精简。
请添加图片描述

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

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

相关文章

springboot项目通过maven的profile功能实现通过不同文件夹的方式来组织不同环境配置文件

写在前面 本文看下springboot项目如何通过文件夹的方式来组织不同环境配置文件。 1&#xff1a;正文 一般的我们写springboot项目时配置文件是这个样子的&#xff1a; appliction.yaml --> 通过spring.profiles.activexxx来激活某个指定后缀的配置文件 application-evn1…

小程序项目实践(一)--项目的初始化以及前期的准备工作

目录 1.起步 1.1 uni-app 简介 1.2 开发工具 1.2.1 下载 HBuilderX 1.2.2 安装 HBuilderX 1.2.3 安装 scss/sass 编译 1.2.4 快捷键方案切换 1.2.5 修改编辑器的基本设置 1.3 新建 uni-app 项目 1.4 目录结构 1.5 把项目运行到微信开发者工具 1.6 使用 Git 管理项目 …

SpringBoot3响应式编程全套-R2DBC

目录 传送门前言一、R2DBC概念二、Spring Data R2DBC1、整合1.1、导入依赖1.2、编写配置 2、声明式接口&#xff1a;R2dbcRepository2.1、Repository接口2.2、自定义Converter2.3、配置生效 3、编程式组件 三、RBAC-SQL练习1、1-12、1-N 四、最佳实践五、附录 传送门 SpringMV…

python配合yolov11开发分类训练软件

上一篇文件写了用yolo分类模型开发分类软件&#xff0c;这边文章在上个分类软件的基础上加入训练功能环境配置:pycharm&#xff0c;PySide6 6.6.1 &#xff0c;PySide6-Addons 6.6.1&#xff0c;PySide6-Essentials 6.6.1&#xff0c;torch 2.3.1cu121&#xff0c;torchaudio 2…

Spring AI Java程序员的AI之Spring AI(三)RAG实战

Spring AI之RAG实战与原理分析 前言RAGDocumentDocumentReaderDocumentTransformerDocumentWriter VectorStoreSimpleVectorStoreRedisVectorStore元数据搜索组装提示词 前言 检索增强生成&#xff08;RAG&#xff09;是一种结合信息检索和生成模型的技术&#xff0c;用于将相…

C语言——数组

1.数组的概念 数组是一组相同类型元素的集合&#xff1b; 数组中可以存放1个或多个元素&#xff0c;但数组元素个数不能为0。 同时数组可以分为一维数组和多维数组&#xff0c;多维数组一般常见 是二维数组。 2.一维数组的创建和初始化 一维数组的创建的基本语法&#xff1a; …

大数据-168 Elasticsearch 单机云服务器部署运行 详细流程

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

【C++】类和对象(类的默认成员函数)

目录 一.构造函数 二.析构函数 三.拷贝构造函数 四.赋值运算符重载 五.取地址运算符重载 默认成员函数就是用户没有显式实现&#xff0c;编译器会自动生成的成员函数称为默认成员函数。一个类&#xff0c;我们不写的情况下编译器会默认生成以下6个默认成员函数。 一.构造…

目标检测中的损失函数

损失函数是用来衡量模型与数据的匹配程度的&#xff0c;也是模型权重更新的基础。计算损失产生模型权重的梯度&#xff0c;随后通过反向传播算法&#xff0c;模型权重得以更新进而更好地适应数据。一般情况下&#xff0c;目标损失函数包含两部分损失&#xff0c;一个是目标框分…

Vue3万能初始化

项目创建后第一步 项目创建&#xff1a;Vue3创建-CSDN博客 创建后执行下面 删除默认提供的HelloWorld.vue组件和src/APP.vue中的默认样式和内容。 App.vue&#xff0c;代码&#xff1a; <template></template><script setup></script><style&g…

数控机械制造工厂ERP适用范围有哪些

在当今制造业高速发展的背景下&#xff0c;企业资源计划(ERP)系统已成为提升工厂管理效率、实现生产自动化与信息化的关键工具。特别是对于数控机械制造工厂而言&#xff0c;一个合适的ERP系统能够帮助其优化生产流程、提高产品质量、降低生产成本并增强市场竞争力。 1. 生产计…

IP数据包格式、ICMP封装步骤

IP数据包格式 版本号&#xff1a;占4位&#xff0c;表示IP协议的版本&#xff0c;目前广泛使用的是IPv4&#xff0c;其版本号为4。 首部长度&#xff1a;占4位&#xff0c;表示IP首部的长度&#xff0c;单位为32位字节。首部长度最小为20字节&#xff0c;最大为60字节。 服务…

dayjs日期格式化,开发uniapp或unicloud前后端进行时间格式转换

一、 为什么要用日期格式化 因为在开发项目过程中&#xff0c;会遇到各种各样的日期格式&#xff0c;有的显示完整的年-月-日 时:分:秒&#xff0c;而有的场景就只显示月-日等格式&#xff0c;还有就是显示当前时间和注册时间的间隔时长等&#xff0c;场景非常多&#xff0c;如…

idea2024年版本

最简单安装2024.2版本idea 内带安装教程 ** 下载链接&#xff1a;https://pan.quark.cn/s/ab24afbaa43f 提取码&#xff1a;KHrq

jmeter发送post请求

在jmeter中&#xff0c;有两种常用的请求方式&#xff0c;get和post.它们两者的区别在于get请求的参数一般是放在路径中&#xff0c;可以使用用户自定义变量和函数助手等方式进行参数化&#xff0c;而post请求的参数不能随url发送&#xff0c;而是作为请求体提交给服务器。而在…

FreeRTOS——中断管理

中断理论剖析 中断简介 中断是一种机制&#xff0c;用于处理高优先级的事件或故障。当一个中断事件发生时&#xff0c;单片机可以立即中断正在执行的程序&#xff0c;转而处理中断事件。这种机制可以提高系统的响应速度和实时性。 中断优先级分组设置 ARM Cortex-M使用了8位宽…

Wed前端入门——HTML、CSS

Wed前端入门——HTML、CSS 一般的页面有HTML、CSS以及JavaScript组成 HTML定义了页面的结构和内容&#xff0c;包括文本、图像、链接等等CSS用于定义页面的布局和样式JS用于添加交互性和动态功能作用 一、HTML 基本格式&#xff1a; <!-- 文档类型为HTML --> <!D…

【C++笔试强训】如何成为算法糕手Day9

学习编程就得循环渐进&#xff0c;扎实基础&#xff0c;勿在浮沙筑高台 循环渐进Forward-CSDN博客 目录 循环渐进Forward-CSDN博客 添加逗号 思路&#xff1a; 代码实现&#xff1a; 跳台阶 思路&#xff1a; 代码实现&#xff1a; 扑克牌顺子 思路&#xf…

收藏!时间序列特征提取最全总结

时间序列数据在很多领域都是重要的结构化数据形式&#xff0c;例如金融、经济、生态学、神经科学和物理学。在多个时间点观测或测量的数据形成了时间序列。许多时间序列是固定频率的&#xff0c;也就是说数据是根据相同的规则定期出现的&#xff0c;例如每15秒、每5分钟或每月1…

高级IO——五种IO模型

一般我们在写一些简单的小项目的时候&#xff0c;免不了会用到IO接口&#xff0c;比如C语言中的scanf/printf又或者是 C中的cout/cin&#xff0c;或者是在Linux操作系统中的文件IO接口read/write。这些接口默认都是阻塞的&#xff0c; 这又引出了阻塞/非阻塞IO的概念&#xff0…