news 2026/6/10 16:54:37

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进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 13:19:48

Windows 11远程桌面多用户配置指南:RDP Wrapper完整教程

还在为Windows 11只能单用户远程连接而烦恼&#xff1f;RDP Wrapper Library这款开源工具能够帮你轻松实现多用户同时远程访问功能&#xff0c;让家庭版系统也能享受企业级的远程桌面体验。无论你是IT管理员、开发者还是普通用户&#xff0c;这份完整配置手册都将为你提供简单实…

作者头像 李华
网站建设 2026/6/9 20:08:56

GitHub热门项目复现:用Qwen-Image-Edit-2509做电商产品图智能修改

GitHub热门项目复现&#xff1a;用Qwen-Image-Edit-2509做电商产品图智能修改 在电商平台的日常运营中&#xff0c;一张主图可能决定一款商品的命运。每逢大促节点&#xff0c;运营团队常常面临这样的困境&#xff1a;几十个SKU需要统一更新价格标签、替换背景文案、调整促销横…

作者头像 李华
网站建设 2026/6/10 14:51:56

9个AI论文工具推荐,本科生期末论文写作轻松搞定

9个AI论文工具推荐&#xff0c;本科生期末论文写作轻松搞定 论文写作的“战场”&#xff1a;时间紧、任务重、压力山大 对于大多数本科生来说&#xff0c;期末论文不仅是对所学知识的一次综合检验&#xff0c;更是对时间管理、写作能力与抗压能力的全面挑战。随着课程内容的不断…

作者头像 李华
网站建设 2026/6/10 11:19:50

大模型微调监控指标:跟踪Qwen3-32B训练过程

大模型微调监控指标&#xff1a;跟踪Qwen3-32B训练过程 在当前大语言模型&#xff08;LLM&#xff09;快速演进的背景下&#xff0c;企业与研究机构正面临一个关键挑战&#xff1a;如何在有限算力资源下&#xff0c;高效微调出性能接近顶级闭源模型的定制化系统。以通义千问系列…

作者头像 李华
网站建设 2026/6/9 20:47:51

8 个文献综述 AI 工具,本科生降重查重率优化推荐

8 个文献综述 AI 工具&#xff0c;本科生降重查重率优化推荐 文献综述的“重担”与时间的“紧逼” 对于大多数本科生来说&#xff0c;论文写作从来不是一件轻松的事情&#xff0c;尤其是当任务涉及到文献综述时&#xff0c;更是让人感到压力山大。文献综述不仅是对已有研究成果…

作者头像 李华