React待办清单实战:从跑通到拆解状态管理与本地持久化
简介这是一份面向 React 初学者与前端进阶者的待办事项清单实战项目源码基于 React.js 构建配合 Node.js、Webpack 与 SCSS 完成工程化与样式组织适合用来练习组件拆分、状态管理与列表增删交互。压缩包共 15 个文件约 280KB其中 7 个 jsx 承载主要组件逻辑2 个 js 与 2 个 json 负责入口配置和依赖声明另有 2 个 html 页面骨架、1 个 scss 样式文件与 1 个 md 说明文档结构紧凑、层次分明。已有 129 人学习关注。项目围绕目标内容的添加与删除展开读者可借此理解受控表单、列表渲染、事件绑定与组件通信等核心知识点并参考其目录组织方式快速搭建自己的 React 练习工程是入门到上手阶段较为实用的参考案例。1. 从一份“有待办事项的待办事项清单”说起它到底能解决什么你有没有过这种体验打开某个待办 App想加一条“买牛奶”结果先弹出来一个引导页再让你选分类、设优先级、绑定日历最后你忘了自己要记什么。这份名为react-todo-list的资源恰恰是反着来的——它本身就是一个待办清单但它的“待办事项”里第一条往往是“把待办清单本身跑起来”。听起来像绕口令实际用起来你会发现它解决的是前端从业者最朴素的一个诉求用最短路径拿到一个能跑、能改、能拆的 React 状态管理样本。它适合三类人刚学完 React 基础语法、想找一个完整小项目练手的新手需要给团队新人准备练手素材的带教者以及想快速验证某个状态管理思路、不想从零搭脚手架的熟手。整个资源围绕 JavaScript 生态展开核心是组件拆分、状态提升、列表渲染与本地持久化这几件事。你不需要先理解 Redux 或 Zustand它大概率就是用useState和useEffect撑起来的但恰恰因为简单你才能看清数据从输入框到列表项再到本地存储的完整链路。下面我按“先跑通、再拆解、后避坑”的顺序把这份资源里里外外过一遍。2. 把项目跑起来环境、依赖与首次渲染的完整链路2.1 先确认你手里的 Node 和包管理器版本拿到任何前端资源我第一件事不是看代码而是看package.json里的engines字段和锁文件。这份资源没有附带说明文档但根据常见 React 项目的配置习惯Node 版本低于 16 会在安装依赖时遇到ERR_OSSL_EVP_UNSUPPORTED这类玄学报错。我一般会先跑两条命令确认环境node -v npm -v如果 Node 是 18 或 20基本可以直接往下走如果是 14 或更早建议用 nvm 切一个 LTS 版本。包管理器方面资源里如果存在package-lock.json就用 npm存在pnpm-lock.yaml就用 pnpm不要混用——混用导致的依赖树错乱是新手翻车的高频场景。确认完版本后进入项目根目录执行安装npm install # 或者 pnpm install这一步会拉取 react、react-dom、react-scripts如果是 CRA 脚手架或 vite 相关依赖。安装完成后先别急着npm start打开package.json看一眼scripts字段确认启动命令到底是start、dev还是serve。不同脚手架的习惯不一样CRA 用startVite 用devNext.js 也是dev。跑错命令会提示 “Missing script”这不是项目坏了只是你喊错了口令。2.2 启动开发服务器并验证首次渲染假设启动命令是npm start执行后终端会输出本地地址通常是http://localhost:3000或http://localhost:5173。浏览器打开后你应该看到一个输入框、一个添加按钮以及下方可能为空的列表区域。如果页面白屏按 F12 打开控制台看有没有红色报错。常见的有两类一是Module not found说明依赖没装全回去补npm install二是React is not defined说明 JSX 转换配置有问题检查jsconfig.json或babel.config.js是否存在且配置正确。首次渲染成功后试着输入一条待办比如“写周报”点击添加。如果列表项正常出现说明核心数据流是通的。此时打开浏览器开发者工具的 Application 面板看 Local Storage 里有没有多出一个键值对。这份资源大概率做了本地持久化键名可能是todos或react-todo-list。如果有刷新页面待办还在说明持久化逻辑生效了。如果没有刷新后列表清空那它就是一个纯内存版本你需要自己补持久化——这反而是个很好的练手点后面章节会讲怎么加。3. 拆开看结构组件拆分、状态提升与本地存储的实现细节3.1 组件树长什么样状态放在哪一层一个典型的 React 待办清单组件树不会太深但状态放置的位置决定了你后续改起来顺不顺手。常见做法是顶层App组件持有todos数组和inputValue字符串通过 props 把todos传给TodoList把inputValue和修改函数传给TodoInput。这种“状态提升到最近公共祖先”的模式是 React 官方文档里反复强调的但新手容易犯的错是把inputValue放在TodoInput内部结果App拿不到输入值添加逻辑就断了。你可以打开src目录找到App.js或App.jsx看useState的调用位置。如果useState出现在TodoInput里而添加函数又在App里那大概率是通过回调把值传上去的这种写法也能跑但状态分散在两处调试时要在两个组件之间跳。我一般会建议把inputValue也提升到App让TodoInput变成一个受控组件只负责展示和触发回调。这样整个应用的状态源只有一个排查问题时只需要看App一个文件。3.2 增删改查四个操作的代码落点待办清单的核心操作就四个添加、删除、切换完成状态、编辑文本。这份资源如果只实现了前三个那编辑功能就是留给你的扩展点。先看添加和删除的典型实现// App.js 中维护 todos 状态 const [todos, setTodos] useState([]); // 添加用扩展运算符生成新数组不要直接 push const addTodo (text) { if (!text.trim()) return; // 空输入直接返回避免产生空待办 const newTodo { id: Date.now(), // 用时间戳做临时 id够用但高并发下可能重复 text: text.trim(), completed: false, }; setTodos((prev) [...prev, newTodo]); }; // 删除用 filter 生成新数组 const deleteTodo (id) { setTodos((prev) prev.filter((todo) todo.id ! id)); }; // 切换完成状态用 map 生成新数组 const toggleTodo (id) { setTodos((prev) prev.map((todo) todo.id id ? { ...todo, completed: !todo.completed } : todo ) ); };这三段代码的逻辑说明React 的状态更新必须是不可变的直接todos.push()不会触发重新渲染这是新手最常踩的坑。setTodos传入函数形式(prev) ...是为了避免闭包捕获旧的todos值在快速连续操作时更安全。id用Date.now()在单用户场景下没问题但如果同一毫秒内添加两条id 会重复导致删除时误删。更稳妥的做法是用crypto.randomUUID()现代浏览器都支持。参数说明text.trim()去掉首尾空格防止用户输入一串空格被当成有效待办。completed字段控制样式通常配合 CSS 类名切换删除线。如果你要加编辑功能思路是给每个 todo 增加一个isEditing标记点击编辑时把text渲染成input失焦或回车时更新text并清除标记。3.3 本地持久化useEffect 的依赖数组怎么写如果资源里已经带了持久化代码大概长这样useEffect(() { const saved localStorage.getItem(todos); if (saved) { setTodos(JSON.parse(saved)); } }, []); // 空依赖只在挂载时执行一次 useEffect(() { localStorage.setItem(todos, JSON.stringify(todos)); }, [todos]); // todos 变化时同步写入第一个useEffect负责初始化读取依赖数组为空确保只在组件挂载时跑一次。第二个useEffect负责写入依赖todos每次待办变化都会更新本地存储。这里有个细节如果初始todos是空数组第二个 effect 会在挂载后立刻把空数组写进去覆盖掉之前保存的数据。所以第一个 effect 的读取必须发生在第二个 effect 的写入之前React 的执行顺序是先跑所有 effect 的清理函数再按顺序跑 effect 本身挂载时两个 effect 都会执行读取在前、写入在后刚好能拿到旧数据。但如果你把两个 effect 的顺序写反了就会出现“刷新后数据丢失”的灵异现象。提示localStorage 只能存字符串所以要用JSON.stringify和JSON.parse转换。如果待办数据量很大超过 5MB 会写入失败控制台报QuotaExceededError。待办清单一般不会遇到但如果你要存图片或附件就得换 IndexedDB。4. 避坑与排查从白屏到数据丢失的五个血泪现场4.1 现象页面白屏控制台报 “Objects are not valid as a React child”原因在 JSX 里直接渲染了一个对象。待办清单里最容易出现的地方是todo本身是个对象你写了{todo}而不是{todo.text}。React 不允许对象作为子元素因为对象转成字符串是[object Object]没有意义。解决检查所有{}里的变量确认渲染的是字符串或数字。如果是日期对象先用toLocaleDateString()转成字符串。如果是嵌套对象用JSON.stringify临时打印出来看结构再决定取哪个字段。4.2 现象点击添加按钮没反应但控制台也不报错原因表单的默认提交行为触发了页面刷新。如果你把添加按钮放在form里且没有阻止默认事件点击按钮会提交表单并刷新页面React 状态全部重置看起来就像“没反应”。解决在表单的onSubmit里调用e.preventDefault()或者把按钮的type显式设为button而不是默认的submit。我一般两个都做双保险。4.3 现象删除一条待办结果删掉了另一条原因key用了数组索引index。当列表顺序变化时React 会复用错误的 DOM 节点导致状态错位。比如你删了第一条原本第二条的索引变成 0React 以为它还是原来那条就把第二条的 DOM 更新成了第一条的内容。解决key必须用稳定且唯一的 id不要用索引。如果数据来自后端用数据库主键如果是前端生成的用crypto.randomUUID()或时间戳加随机数。这份资源如果用了索引做 key建议你手动改掉这是性价比最高的一个修复。4.4 现象刷新后待办全部消失但 localStorage 里明明有数据原因读取时机不对。如果你在useState初始化时直接读 localStorage比如useState(localStorage.getItem(todos))读出来的是字符串不是数组后续map会报错。或者你在组件挂载前就读了此时 localStorage 还没准备好虽然极少见。解决用useState的惰性初始化传一个函数进去useState(() JSON.parse(localStorage.getItem(todos)) || [])。这样只在首次渲染时读一次且做了空值兜底。或者用前面说的useEffect方案挂载后再读。4.5 现象输入中文时每敲一个字母就触发一次添加原因用了onChange直接触发添加逻辑而不是先存到inputValue再在提交时添加。中文输入法在拼写阶段会频繁触发input事件如果onChange里直接调addTodo就会产生一堆半成品待办。解决onChange只更新inputValue添加操作绑定在按钮点击或回车键的onKeyDown上。如果要在输入过程中做实时搜索用防抖函数包一层延迟 300ms 再执行。5. 进阶改造给待办清单加上过滤、编辑与拖拽排序跑通基础版本后这份资源最大的价值在于它是一个干净的画布。我一般会按三个方向改造每个方向都能让你对 React 状态管理的理解加深一层。第一个方向是过滤视图。在App里加一个filter状态取值all、active、completed然后根据filter计算派生列表const filteredTodos todos.filter((todo) { if (filter active) return !todo.completed; if (filter completed) return todo.completed; return true; });注意这里不要用useState存过滤后的列表而是每次渲染时从todos和filter计算出来。这样避免了两个状态不同步的问题——你删了一条待办过滤列表自动更新不需要手动同步。这是 React 里“单一数据源”原则的典型应用。第二个方向是行内编辑。给每个TodoItem加一个isEditing状态双击文本时切换为输入框失焦或回车时提交修改。这里有个坑如果isEditing放在TodoItem内部而todos在App里编辑提交后要调用App传下来的updateTodo函数。状态分散但逻辑清晰是可以接受的。另一种做法是把editingId提升到App只允许同时编辑一条实现更简单看你取舍。第三个方向是拖拽排序。这需要引入第三方库常见做法是用dnd-kit/sortable或react-beautiful-dnd。以dnd-kit为例安装后把TodoList包在DndContext里每个TodoItem用useSortable绑定拖拽结束时用arrayMove重新排列todos数组。参数上要注意activationConstraint设一个小的距离阈值否则点击和拖拽会冲突导致想点完成却触发了拖拽。改造方向新增依赖核心 API容易翻车的点过滤视图无Array.filter用状态存派生数据导致不同步行内编辑无受控 input 失焦事件编辑态与全局状态不同步拖拽排序dnd-kit/coreuseSortable、arrayMove点击与拖拽事件冲突验证改造是否成功我习惯用一套固定动作添加三条待办切换其中一条为完成过滤到 active 视图确认只剩两条再切回 all双击编辑一条文本刷新页面确认所有修改都持久化了。这套动作走完没问题基本就能交付给其他人用了。从那以后我每次拿到一个前端小项目都会先跑通再拆组件树最后按这套固定动作验一遍很少再出现“本地好好的、别人一跑就崩”的尴尬。希望这份拆解能帮到你。本文还有配套的精品资源点击获取

相关新闻

MyBatis逆向工程:从数据库Schema到可维护Mapper的工程化实践

MyBatis逆向工程:从数据库Schema到可维护Mapper的工程化实践

1. 项目概述:为什么“MyBatis逆向工程”不是偷懒捷径,而是团队提效的底层基建你有没有经历过这样的场景:一个新数据库表上线,字段12个,关联3张字典表,业务接口要查、要改、要分页、要导出——光是手写Mappe…

2026/10/14 19:58:07 阅读更多 →
真题资源高效利用:从分类索引到三轮刷题法的完整训练指南

真题资源高效利用:从分类索引到三轮刷题法的完整训练指南

简介:这是一份面向蓝桥杯参赛者的历年真题合集,涵盖省赛与国赛两个层级的代表性赛题,适用于正在备赛的本科、高职院校学生及指导老师。资源以rar压缩包形式整体打包,大小约62.1MB,便于一次性获取多届试题并离线使用&am…

2026/10/14 19:58:07 阅读更多 →
TypeScript协议适配:将Claude Code前端无缝对接Deepseek模型

TypeScript协议适配:将Claude Code前端无缝对接Deepseek模型

1. 这不是“换壳”,而是一次精准的协议层手术“80行 TypeScript Mods,把 Claude Code 改造成 Deepseek Harness”——这个标题乍看像极了某些技术圈里常见的“魔改教程”,但实际操作中,我很快意识到:它根本不是在 UI 上…

2026/10/14 19:57:05 阅读更多 →

最新新闻

Towards Automated Regulatory Compliance Verification in Financial Auditing with Large Language Mo...

Towards Automated Regulatory Compliance Verification in Financial Auditing with Large Language Mo...

文章主要内容总结 本文聚焦于利用大型语言模型(LLMs)实现财务审计中监管合规性的自动验证,旨在解决传统审计中人工验证合规性的低效问题。研究对比了开源LLMs(如Llama-2系列)与专有LLMs(如OpenAI的GPT系列)在合规性检测中的性能,使用了普华永道(PwC)提供的两个自定义…

2026/10/14 20:48:13 阅读更多 →
A Versatile Pathology Co-pilot via Reasoning Enhanced Multimodal Large Language Model

A Versatile Pathology Co-pilot via Reasoning Enhanced Multimodal Large Language Model

文章主要内容和创新点总结 主要内容 本文提出了一种名为SmartPath-R1的多模态大型语言模型(MLLM),旨在解决计算病理学中现有模型推理能力有限、任务适应性单一的问题。该模型能够同时处理区域感兴趣(ROI)级别和全切片图像(WSI)级别的任务,包括分类、检测、分割和视觉…

2026/10/14 20:48:13 阅读更多 →
The Pluralistic Moral Gap: Understanding Judgment and Value Differences between Humans and Large ...

The Pluralistic Moral Gap: Understanding Judgment and Value Differences between Humans and Large ...

文章主要内容总结 本文聚焦大型语言模型(LLMs)与人类道德判断的差异,通过构建真实世界道德困境数据集,系统分析了二者在道德判断分布和价值观表达上的“多元道德差距”,并提出了缩小该差距的方法。具体内容如下: 数据集构建:创建了包含1618个真实世界道德困境的“道德困…

2026/10/14 20:48:13 阅读更多 →
GBS光子采样加速稠密子图搜索:图论难题的量子启发式解法

GBS光子采样加速稠密子图搜索:图论难题的量子启发式解法

1. 这不是量子计算科普,而是一次图论问题的“量子启发式突围” 你可能在最近几篇预印本论文或某次学术分享中见过这个标题:“Gaussian Boson Sampling for finding dense subgraphs”。它听起来像一个典型的交叉学科缝合怪——把高能物理里的玻色采样、量…

2026/10/14 20:48:13 阅读更多 →
风电功率预测的精度密码:输入稳定性硬指标建设指南

风电功率预测的精度密码:输入稳定性硬指标建设指南

1. 数据还是模型:先搞清楚精度瓶颈到底在哪先说一个我自己的感受。入行风电功率预测这几年,身边绝大多数团队把精力都砸在模型结构上:今天换一套神经网络,明天堆一个集成学习,后天又有人说注意力机制效果好。每次模型迭…

2026/10/14 20:48:13 阅读更多 →
基于STM32的简易四轴飞行器:硬件选型、姿态解算与PID调参全攻略

基于STM32的简易四轴飞行器:硬件选型、姿态解算与PID调参全攻略

简介:基于STM32的直流电机速度环PID闭环控制资源包,面向嵌入式初学者与电子类课程设计学生,帮助理解反馈控制原理并解决直流电机调速中的闭环实现问题。压缩包共204个文件,主要由C源文件、H头文件、Keil工程配置文件(u…

2026/10/14 20:47:12 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 22:01:27 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 7:53:34 阅读更多 →