构建 React Todo 应用:组件通信与状态管理的最佳实践

Todo 应用虽小,却是检验框架理解深度的"试金石"。它涵盖了状态管理、组件拆分、数据流控制、本地持久化等核心概念。使用 React 构建这样一个应用,不仅能体现函数式编程与组件化思想的优势,更能清晰展示父子组件通信、状态提升与单向数据流 的设计哲学。

状态集中管理:单一数据源原则

React 推崇"状态提升"------将共享状态置于最近的共同父组件中。在 Todo 应用中,所有待办事项 todos 被统一管理在 App 组件内:

复制代码
const [todos, setTodos] = useState(() => {
  const saved = localStorage.getItem('todos');
  return saved ? JSON.parse(saved) : [];
});

通过 useState 的函数式初始化,应用启动时自动从 localStorage 恢复历史数据。这种设计确保了整个应用只有一个"真相来源",避免了状态分散导致的不一致问题。

子组件通信:通过 Props 传递数据与行为

子组件如 TodoInputTodoListTodoStats 均不持有自身状态,而是通过 props 接收数据和操作方法:

复制代码
<TodoInput onAdd={addTodo} />
<TodoList 
  todos={todos} 
  onDelete={deleteTodo}
  onToggle={toggleTodo}
/>
<TodoStats 
  total={todos.length}
  active={activeCount}
  completed={completedCount}
  onClearCompleted={clearCompleted}
/>
  • TodoInput 接收 onAdd 回调,用于提交新任务;
  • TodoList 接收任务列表及删除、切换完成状态的方法;
  • TodoStats 显示统计信息并提供清除已完成项的功能。

这种模式严格遵循单向数据流 :数据自上而下传递,修改请求自下而上传递。子组件无法直接修改 todos,只能调用父组件提供的函数发起变更,确保状态演进的可预测性。

子到父通信:回调函数作为事件通道

React 不支持子组件直接修改父状态,但可通过回调函数实现"事件上报"。例如,TodoInput 在表单提交时调用 onAdd

复制代码
const handleSubmit = (e) => {
  e.preventDefault();
  onAdd(inputValue);
  setInputValue('');
};

onAdd 实际是 App 中定义的 addTodo 函数,它接收文本并生成新任务:

复制代码
 const addTodo = (text) => {
  setTodos([...todos, {
    id: Date.now(),
    text,
    completed: false
  }]);
};

类似地,TodoList 中的复选框和删除按钮分别触发 onToggleonDelete,将用户操作转化为对中心状态的更新请求。这种机制解耦了 UI 与逻辑,使组件更专注于自身职责。

兄弟组件通信:间接通过父组件协调
TodoInputTodoListTodoStats 是兄弟关系,彼此无直接引用。它们的数据同步完全依赖父组件 App 的协调:

  • TodoInput 添加新任务,App 更新 todos
  • todos 作为 props 传递给 TodoListTodoStats
  • 二者自动重新渲染,显示最新内容。

这种"间接通信"看似绕路,实则保证了数据流的清晰与可追踪。任何状态变化都源于明确的父级更新,极大降低了调试复杂度。

本地持久化:副作用中的数据同步

为防止页面刷新丢失数据,应用需将 todos 同步至 localStorage。这属于典型的副作用操作,由 useEffect 处理:

复制代码
 useEffect(() => {
  localStorage.setItem('todos', JSON.stringify(todos));
}, [todos]);

每当 todos 发生变化(依赖项 [todos] 触发),该副作用自动执行,将最新状态写入存储。这种声明式写法将持久化逻辑与业务逻辑分离,保持主渲染路径的纯净。

样式与用户体验:Stylus 与条件渲染

项目采用 Stylus 预处理器编写样式,配合 React 的条件类名实现动态 UI:

复制代码
<li className={todo.completed ? 'completed' : ''}>

当任务完成时,添加 completed 类,应用删除线等视觉反馈。同时,TodoStats 仅在存在已完成项时显示"清除"按钮:

复制代码
 {completed > 0 && <button onClick={onClearCompleted}>Clear Completed</button>}

这种细粒度的控制提升了界面的响应性与友好度。

总结

这个 Todo 应用虽功能简单,却完整体现了 React 的核心思想:组件化、单向数据流、状态集中管理与副作用隔离 。通过将状态置于顶层、通过 Props 传递数据与回调、利用 useEffect 处理持久化,代码结构清晰、逻辑内聚、易于扩展。无论是初学者理解 React 原理,还是团队建立开发规范,此类实践都提供了坚实的基础。掌握这些模式,便能在更复杂的业务场景中游刃有余地构建健壮、可维护的前端应用。

原文: https://juejin.cn/post/75917028

相关推荐
web小白成长日记几秒前
企业级 Vue3 + Element Plus 主题定制架构:从“能用”到“好用”的进阶之路
前端·架构
APIshop34 分钟前
Python 爬虫获取 item_get_web —— 淘宝商品 SKU、详情图、券后价全流程解析
前端·爬虫·python
风送雨42 分钟前
FastMCP 2.0 服务端开发教学文档(下)
服务器·前端·网络·人工智能·python·ai
XTTX11042 分钟前
Vue3+Cesium教程(36)--动态设置降雨效果
前端·javascript·vue.js
LYFlied2 小时前
WebGPU与浏览器边缘智能:开启去中心化AI新纪元
前端·人工智能·大模型·去中心化·区块链
Setsuna_F_Seiei2 小时前
2025 年度总结:人生重要阶段的一年
前端·程序员·年终总结
model20052 小时前
alibaba linux3 系统盘网站迁移数据盘
java·服务器·前端
han_3 小时前
从一道前端面试题,谈 JS 对象存储特点和运算符执行顺序
前端·javascript·面试
aPurpleBerry3 小时前
React 01 目录结构、tsx 语法
前端·react.js
jayaccc3 小时前
微前端架构实战全解析
前端·架构