news 2026/2/28 10:27:19

react中的使用useReducer和Context实现todolist

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
react中的使用useReducer和Context实现todolist

store.ts - 类型定义 + 初始状态

import { nanoid } from 'nanoid' // 定义单个 Todo 的类型(约束结构:id+标题) export type TodoType = { id: string title: string } // 初始状态:一个包含2个Todo的数组,用nanoid生成唯一id const initialState: TodoType[] = [ { id: nanoid(5), title: '吃饭' }, { id: nanoid(5), title: '睡觉' }, ] export default initialState

作用:

• 用 TypeScript 约束 Todo 数据结构,避免类型错误;

• 定义初始的 Todo 列表,作为 useReducer 的初始值;

• nanoid:生成短且唯一的 ID(替代 UUID,更轻量)。

reducer.ts - 状态更新逻辑(核心)

import type { TodoType } from './store' // 定义动作类型(type:动作标识,payload:附加数据) export type ActionType = { type: string payload?: any // 可传:新增的Todo对象 / 要删除的Todo ID } // reducer是纯函数:接收「当前状态」和「动作」,返回「新状态」 export default function reducer(state: TodoType[], action: ActionType) { switch (action.type) { // 新增Todo:用concat返回新数组(不可变,不修改原state) case 'add': return state.concat(action.payload) // 删除Todo:用filter过滤掉目标ID,返回新数组 case 'delete': return state.filter(todo => todo.id !== action.payload) // 未知动作抛错,避免逻辑遗漏 default: throw new Error() } }

核心原则

  • 纯函数:无副作用、输入相同则输出相同;
  • 不可变数据:绝不直接修改state(如state.push()是错误的),而是返回新数组(concat/filter),保证 React 能检测到状态变化并重新渲染。

index.tsx - 根组件 + Context 提供

import React, { FC, createContext, useReducer } from 'react' import reducer, { ActionType } from './reducer' import initialState from './store' import List from './List' import InputForm from './InputForm' // 1. 创建Context:定义上下文的类型(包含state和dispatch),并设置默认值(空实现) export const TodoContext = createContext({ state: initialState, dispatch: (action: ActionType) => {}, }) const Demo: FC = () => { // 2. 初始化useReducer:接收reducer和初始状态,返回[当前状态, 派发动作的函数] const [state, dispatch] = useReducer(reducer, initialState) return ( // 3. 用Context.Provider包裹子组件,把state和dispatch注入上下文 <TodoContext.Provider value={{ state, dispatch }}> <p>Todo list by useReducer</p> <List /> {/* 子组件:展示Todo */} <InputForm /> {/* 子组件:新增Todo */} </TodoContext.Provider> ) } export default Demo

关键作用:

• createContext:创建跨组件通信的上下文,让子组件无需通过 props 传递状态;

• useReducer:替代 useState 管理复杂状态(多动作类型:新增 / 删除);

• Provider:把 state(当前 Todo 列表)和 dispatch(触发状态更新的函数)暴露给所有子组件。

InputForm.tsx - 新增 Todo 组件

import React, { FC, ChangeEvent, useState, useContext } from 'react' import { nanoid } from 'nanoid' import { TodoContext } from './index' const InputForm: FC = () => { // 从Context中获取全局的state和dispatch const { state, dispatch } = useContext(TodoContext) // 局部状态:管理输入框的文字(无需全局共享,所以用useState) const [text, setText] = useState('') // 输入框变化时:更新局部状态text function handleChange(event: ChangeEvent<HTMLInputElement>) { setText(event.target.value) } // 提交表单时:新增Todo function handleSubmit(event: ChangeEvent<HTMLFormElement>) { event.preventDefault() // 阻止表单默认提交行为 if (!text.trim()) return // 空内容不处理 // 构建新Todo对象 const newTodo = { id: nanoid(5), title: text, } // 派发「add」动作:传递新Todo作为payload dispatch({ type: 'add', payload: newTodo }) setText('') // 清空输入框 } return ( <form onSubmit={handleSubmit}> <label htmlFor="new-todo">What needs to be done?</label> <br /> <input id="new-todo" onChange={handleChange} value={text} /> {/* 按钮文字:展示下一个Todo的序号(state.length+1) */} <button type="submit">Add #{state.length + 1}</button> </form> ) } export default InputForm

核心逻辑:

• 局部状态 text:管理输入框内容(仅组件内使用,无需全局);

• handleSubmit:校验内容 → 构建新 Todo → 调用 dispatch 派发 add 动作 → 清空输入;

• useContext(TodoContext):从上下文获取全局的 dispatch,触发状态更新。

List.tsx - 展示 / 删除 Todo 组件

import React, { FC, useContext } from 'react' import { TodoContext } from './index' const List: FC = () => { // 从Context中获取全局state和dispatch const { state, dispatch } = useContext(TodoContext) // 删除Todo:派发「delete」动作,传递要删除的ID作为payload function del(id: string) { dispatch({ type: 'delete', payload: id }) } return ( <ul> {/* 遍历state,渲染每个Todo */} {state.map(todo => ( <li key={todo.id}> {/* key必须唯一,用Todo的id */} <span>{todo.title}</span> {/* 点击删除按钮,调用del并传递当前Todo的id */} <button onClick={() => del(todo.id)}>删除</button> </li> ))} </ul> ) } export default List

核心逻辑:

• 遍历全局 state 渲染 Todo 列表;

• 每个删除按钮绑定 del 方法,派发 delete 动作并传递目标 ID;

• 同样通过 useContext 获取全局状态和更新方法。

核心用法总结

1. useReducer 用法

const [state, dispatch] = useReducer(reducer函数, 初始状态)

state:当前最新的状态(这里是 Todo 数组);

• dispatch:派发动作的函数,格式:dispatch({ type: '动作名', payload: 附加数据 });

• reducer:根据 action.type 处理不同逻辑,返回新状态(必须保证不可变)。

2. Context 跨组件通信用法

1. 创建 Context:createContext(默认值);

2. 提供 Context:Context.Provider value={{ 要共享的数据/方法 }};

3. 消费 Context:子组件用 useContext(Context) 获取共享内容。

3. 不可变数据的常用操作

4. 局部状态 vs 全局状态 • 全局状态:

Todo 列表(需要在 List/InputForm 共享)→ 用 useReducer + Context;

• 局部状态:输入框文字(仅 InputForm 用)→ 用 useState。

四、流程梳理(新增 / 删除 Todo)

新增 Todo 流程:

1. 用户在 InputForm 输入框输入内容 → handleChange 更新局部状态 text;

2. 点击提交按钮 → handleSubmit 校验内容,构建新 Todo 对象;

3. 调用 dispatch({ type: 'add', payload: 新Todo });

4. reducer 接收到 add 动作 → 用 concat 返回新的 Todo 数组;

5. useReducer 检测到状态变化 → 更新 state;

6. Context 把新 state 传递给 List 组件 → List 重新渲染,展示新 Todo。

删除 Todo 流程:

1. 用户点击 List 中某 Todo 的删除按钮 → 调用 del(id);

2. del 方法调用 dispatch({ type: 'delete', payload: id });

3. reducer 接收到 delete 动作 → 用 filter 返回过滤后的新数组;

4. useReducer 更新 state → List 重新渲染,移除被删除的 Todo。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/28 7:47:24

玩转SM16714PHT景观装饰驱动IC(1)

一、概述 1. 芯片简介 SM16714PHT是深圳市明微电子股份有限公司推出的一款单线传输四通道LED驱动控制专用芯片&#xff0c;采用单线归零码SID数据协议。 SM16714PHT可通过芯片内之的电流增益调节功能设置电流2.5mA~40mA&#xff0c;OUT R/G/B/W各32级电流增益&#xff08;即…

作者头像 李华
网站建设 2026/2/27 12:11:22

云服务器的核心优势

云服务器作为新一代计算服务模式&#xff0c;正逐步替代传统物理服务器成为企业数字化转型的基础设施核心。其通过虚拟化技术整合计算资源&#xff0c;结合网络分布式架构实现弹性扩展&#xff0c;为用户带来远超传统IT架构的综合价值。以下从技术架构、成本控制、业务支撑等维…

作者头像 李华
网站建设 2026/2/26 10:44:08

Qwen3-14B-AWQ:重新定义轻量化大模型效率标准

在2025年AI大模型领域&#xff0c;Qwen3-14B-AWQ以其革命性的14.8亿参数设计和AWQ 4-bit量化技术&#xff0c;正在重塑企业级AI部署的性价比认知。这款来自阿里巴巴通义千问团队的开源模型&#xff0c;不仅将硬件门槛降低至消费级GPU水平&#xff0c;更在性能保持率上实现了97%…

作者头像 李华
网站建设 2026/2/27 10:36:22

Linux环境下的C语言编程(三十九)

三、队列的基本操作&#xff08;接三十八&#xff09;1. 基本数据结构定义#include <stdio.h> #include <stdlib.h> #include <stdbool.h>#define MAX_SIZE 100 // 队列最大容量// 队列结构体定义 typedef struct {int data[MAX_SIZE]; // 存储数据的数组i…

作者头像 李华
网站建设 2026/2/27 6:33:20

毕业设计实战:基于SSM+MySQL的图书商城管理系统设计与实现,从需求到测试全流程拆解,新手也能轻松通关!

毕业设计实战&#xff1a;基于SSMMySQL的图书商城管理系统设计与实现&#xff0c;从需求到测试全流程拆解&#xff0c;新手也能轻松通关&#xff01; 谁懂啊&#xff01;当初做图书商城管理系统毕设时&#xff0c;光“图书表”和“图书收藏表”的外键关联就卡了2天——一开始没…

作者头像 李华