news 2026/1/11 1:49:41

react中todolist小案例

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
react中todolist小案例

Todolist.tsx

import React, { useState } from "react"; // 引入 Redux 相关的 Hooks import { useDispatch, useSelector } from "react-redux"; // 引入刚才定义的 Actions,用于触发状态变更 import { addTodo, removeTodo, toggleCompleted } from "../store/todoList"; // 引入 nanoid 用于生成 ID import { nanoid } from "nanoid"; // 引入 RootState 类型,用于类型推断 import type { RootState } from "../store/index"; // 引入 TodoItemType 类型,用于定义本地状态类型 import type { TodoItemType } from "../store/todoList"; /** * TodoList 函数式组件 * 实现了待办事项的增、删、改(状态切换)功能 */ const TodoList = () => { // --- 本地状态 (Component State) --- // 用于管理输入框的受控组件状态 const [inputValue, setInputValue] = useState(""); // --- Redux 状态与方法 --- // 获取 dispatch 函数,用于向 store 发送指令 const dispatch = useDispatch(); // 从 Redux Store 中选取 todos 数据 // 使用泛型 <RootState> 帮助 TypeScript 推断 state 结构 // 使用 `as TodoItemType[]` 进行类型断言(或者确保 RootState 中的 todos 类型定义正确) const todos = useSelector<RootState>((state) => state.todos) as TodoItemType[]; // --- 事件处理函数 --- /** * 处理添加 Todo 的逻辑 */ const handleAddTodo = () => { // 1. 校验输入是否为空 if (inputValue.trim() !== "") { // 2. 构造新的 Todo 对象 const newTodo: TodoItemType = { id: nanoid(5), // 生成短 ID text: inputValue, completed: false, // 默认未完成 }; // 3. 派发 addTodo Action // 注意:这里传入的是整个 Todo 对象,与 Slice 中定义的 PayloadAction<TodoItemType> 对应 dispatch(addTodo(newTodo)); // 4. 清空输入框 setInputValue(""); } }; /** * 处理删除 Todo * @param id - 要删除的 Todo 的 ID */ const handleRemoveTodo = (id: string) => { // 派发 removeTodo Action // 注意:这里传入的是 { id: 'xxx' },与 Slice 中定义的 PayloadAction<{id: string}> 对应 dispatch(removeTodo({ id })); }; /** * 处理切换完成状态 * @param id - 要切换状态的 Todo 的 ID */ const handleToggleCompleted = (id: string) => { dispatch(toggleCompleted({ id })); }; // --- 渲染 JSX --- return ( <> <h2>Todo List</h2> <div> {/* 双向绑定输入框 */} <input type="text" value={inputValue} // 更新本地状态 onChange={(e) => setInputValue(e.target.value)} placeholder="Enter a new todo" /> {/* 绑定添加事件 */} <button onClick={handleAddTodo}>Add</button> </div> <ul> {/* 遍历从 Redux 获取的列表 */} {todos.map((todo) => ( <li key={todo.id}> {/* 复选框绑定 completed 状态 */} <input type="checkbox" checked={todo.completed} // 触发状态切换 onChange={() => handleToggleCompleted(todo.id)} /> {/* 根据 completed 状态动态添加删除线样式 */} <span style={{ textDecoration: todo.completed ? "line-through" : "none", }} > {todo.text} </span> {/* 删除按钮 */} <button onClick={() => handleRemoveTodo(todo.id)}>Delete</button> </li> ))} </ul> </> ); }; export default TodoList;

todoList.ts

// 引入 createSlice 用于创建切片(包含 action 和 reducer) import { createSlice } from "@reduxjs/toolkit"; // 引入 PayloadAction 类型,用于给 reducer 中的 action 定义 payload 的类型 import type { PayloadAction } from "@reduxjs/toolkit"; // 引入 nanoid 用于生成唯一的 ID import { nanoid } from "nanoid"; // --- 类型定义 --- /** * 定义 Todo 项目的类型 */ export type TodoItemType = { id: string; // 唯一标识符 text: string; // 任务描述文本 completed: boolean; // 标记任务是否已完成 }; // --- 初始状态 --- /** * 定义 Todo 列表的初始状态 * 包含两条示例数据 */ const INIT_STATE: TodoItemType[] = [ { id: nanoid(5), text: "learn redux", completed: false, }, { id: nanoid(5), text: "learn typescript", completed: false, }, ]; // --- Slice 创建 --- /** * 创建 TodoList 的 Slice * Slice 会自动生成对应的 action creators 和 reducer 逻辑 */ export const todoListSlice = createSlice({ name: "todoList", // Action type 的前缀,例如:todoList/addTodo initialState: INIT_STATE, // 初始状态数组 reducers: { /** * 添加 Todo 的 Reducer * @param state - Immer 代理的 Draft 状态,可以直接"修改"或返回新状态 * @param action - 包含 payload (新 Todo 对象) 的动作 */ addTodo: (state, action: PayloadAction<TodoItemType>) => { // 方式一:返回新数组 (不可变更新) // return [...state, action.payload]; // 方式二:使用 Immer 推荐的"直接修改"语法 (底层会自动生产新状态) // 这里我们把新任务添加到数组末尾 state.push(action.payload); }, /** * 删除 Todo 的 Reducer * @param action.payload - 一个包含 id 字段的对象,用于指定删除哪个任务 */ removeTodo: (state, action: PayloadAction<{ id: string }>) => { // 解构出要删除的 ID const { id: removeId } = action.payload; // 查找该 ID 对应的索引 const index = state.findIndex((item) => item.id === removeId); // 如果找到了,使用 splice 直接删除 (Immer 允许这种写法) if (index !== -1) { state.splice(index, 1); } }, /** * 切换任务完成状态的 Reducer * @param action.payload - 一个包含 id 字段的对象,用于指定切换哪个任务 */ toggleCompleted: (state, action: PayloadAction<{ id: string }>) => { const { id: toggleId } = action.payload; // 在数组中查找对应的 Todo 项 const todo = state.find((item) => item.id === toggleId); // 如果找到了,直接取反它的 completed 属性 if (todo) { todo.completed = !todo.completed; } }, }, }); // --- 导出 Actions 和 Reducer --- // 导出生成的 Action Creators,用于在组件中 dispatch export const { addTodo, removeTodo, toggleCompleted } = todoListSlice.actions; // 导出 reducer,用于注入到 Redux Store 中 export default todoListSlice.reducer;

app.tsx

import { useState } from 'react' import './App.css' import Count from './pages/Count' import TodoList from './pages/TodoList' function App(){ return ( <> <h1>Redux Demo</h1> <Count /> <TodoList /> </> ) } export default App
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2025/12/15 22:39:24

Clumsy 工具指南

Clumsy 工具简介 Clumsy 是一款开源的弱网模拟工具&#xff0c;适用于 Windows 系统&#xff08;Win7 及以上&#xff09;&#xff0c;无需安装&#xff0c;绿色运行但需管理员权限。它能通过实时修改网络数据包&#xff0c;模拟以下弱网场景&#xff1a; 丢包&#xff08;Pa…

作者头像 李华
网站建设 2025/12/15 22:38:23

GitHub Issue追踪Qwen-Image-Edit-2509已知Bug与修复进度

GitHub Issue追踪Qwen-Image-Edit-2509已知Bug与修复进度 在电商运营、社交媒体内容创作等高频视觉处理场景中&#xff0c;一张产品图的微小调整——比如更换文案、移除模特、替换背景——往往需要设计师反复打开Photoshop&#xff0c;手动抠图、填充、调色。这个过程不仅耗时&…

作者头像 李华
网站建设 2026/1/10 12:50:27

傅里叶变换、拉普拉斯变换、Z 变换的定义及关系

文章目录一、 三种变换的定义1. 连续时间信号的傅里叶变换&#xff08;FT&#xff09;2. 连续时间信号的拉普拉斯变换&#xff08;LT&#xff09;3. 离散时间信号的Z变换&#xff08;ZT&#xff09;二、 三种变换的关系1. 傅里叶变换与拉普拉斯变换的关系2. 傅里叶变换与 Z 变换…

作者头像 李华
网站建设 2025/12/15 22:38:06

C#特性(Attributes)详解

第一部分&#xff1a;特性是什么&#xff1f;&#xff08;类比贴标签&#xff09;1.1 最简单的理解想象一下你在图书馆看书&#xff0c;你可能会&#xff1a;在重要的页面贴书签&#xff08;标记重要内容&#xff09;在书封面上贴标签&#xff08;如"新书"、"推…

作者头像 李华
网站建设 2025/12/19 8:16:04

8 个文献综述工具推荐,本科生论文写作更轻松!

8 个文献综述工具推荐&#xff0c;本科生论文写作更轻松&#xff01; 论文写作的“三座大山”&#xff1a;时间、重复率与效率 对于本科生来说&#xff0c;毕业论文从来不是一件轻松的事情。尤其是文献综述部分&#xff0c;常常让人感到无从下手。面对海量的学术资料&#xff0…

作者头像 李华
网站建设 2025/12/15 22:36:25

9 个开题演讲稿 AI 工具,本科生论文写作推荐

9 个开题演讲稿 AI 工具&#xff0c;本科生论文写作推荐 论文路上的“三座大山”&#xff1a;时间、重复率与灵感枯竭 对于每一位本科生来说&#xff0c;撰写开题报告和演讲稿都是一段既紧张又充满挑战的旅程。从选题到文献综述&#xff0c;从框架搭建到内容填充&#xff0c;…

作者头像 李华