news 2026/8/22 0:12:28

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/8/22 0:47:01

基于HunyuanVideo-Foley的智能音效同步方案在GitHub引发开发者热议

基于HunyuanVideo-Foley的智能音效同步方案在GitHub引发开发者热议 短视频时代&#xff0c;内容创作者每天都面临一个尴尬的问题&#xff1a;画面拍得极具张力&#xff0c;可声音却空空如也。补录脚步声、添加碰撞音效、调整背景氛围……这些看似细微的工作&#xff0c;往往需要…

作者头像 李华
网站建设 2026/8/21 11:03:54

10个毕业答辩PPT神器,研究生AI工具推荐

10个毕业答辩PPT神器&#xff0c;研究生AI工具推荐 论文写作的“三座大山”&#xff1a;时间、重复率与效率的挑战 对于研究生而言&#xff0c;毕业答辩不仅是一场学术成果的展示&#xff0c;更是一次对个人综合能力的全面考验。从选题到开题报告&#xff0c;从文献综述到实验设…

作者头像 李华
网站建设 2026/8/22 0:38:40

【Coze - AI Agent 开发平台】-- 你真的了解 Coze 吗

&#x1f52d; 个人主页&#xff1a;散峰而望 《C语言&#xff1a;从基础到进阶》《编程工具的下载和使用》《C语言刷题》《算法竞赛从入门到获奖》《人工智能AI学习》《AI Agent》 愿为出海月&#xff0c;不做归山云&#x1f3ac;博主简介 文章目录前言1. 什么是 coze2. 为什么…

作者头像 李华
网站建设 2026/8/21 21:06:46

Zotero文献去重终极指南:智能合并重复条目的完整教程

Zotero文献去重终极指南&#xff1a;智能合并重复条目的完整教程 【免费下载链接】ZoteroDuplicatesMerger A zotero plugin to automatically merge duplicate items 项目地址: https://gitcode.com/gh_mirrors/zo/ZoteroDuplicatesMerger 还在为Zotero文献库中大量的重…

作者头像 李华
网站建设 2026/8/21 21:07:01

HuggingFace Spaces快速部署Qwen3-VL-30B在线演示应用

HuggingFace Spaces快速部署Qwen3-VL-30B在线演示应用 在多模态AI迅速演进的今天&#xff0c;一个现实问题始终困扰着开发者&#xff1a;如何让拥有300亿参数的大模型走出实验室&#xff0c;真正被用户“看见、试用、反馈”&#xff1f;尤其是在视觉语言任务中&#xff0c;研究…

作者头像 李华
网站建设 2026/8/21 21:05:58

警惕AI的“脑补”神技:大模型幻觉 (AI Hallucination) 完全指南

生活中的例子 01- 律师用ChatGPT写法律文书&#xff0c;结果AI引用了根本不存在的最高法院案例。生活中的例子 02- 程序员让AI推荐一个代码库&#xff0c;AI给出了一个名字极其逼真但实际不存在的库名。生活中的例子 03- 学生问AI某位不知名历史人物的生平&#xff0c;AI把另一…

作者头像 李华