Todo 应用虽小,却是检验框架理解深度的"试金石"。它涵盖了状态管理、组件拆分、数据流控制、本地持久化等核心概念。使用 React 构建这样一个应用,不仅能体现函数式编程与组件化思想的优势,更能清晰展示父子组件通信、状态提升与单向数据流的设计哲学。
状态集中管理:单一数据源原则
React 推崇"状态提升"------将共享状态置于最近的共同父组件中。在 Todo 应用中,所有待办事项 todos 被统一管理在 App 组件内:
ini
const [todos, setTodos] = useState(() => {
const saved = localStorage.getItem('todos');
return saved ? JSON.parse(saved) : [];
});
通过 useState 的函数式初始化,应用启动时自动从 localStorage 恢复历史数据。这种设计确保了整个应用只有一个"真相来源",避免了状态分散导致的不一致问题。
子组件通信:通过 Props 传递数据与行为
子组件如 TodoInput、TodoList 和 TodoStats 均不持有自身状态,而是通过 props 接收数据和操作方法:
ini
<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:
ini
const handleSubmit = (e) => {
e.preventDefault();
onAdd(inputValue);
setInputValue('');
};
onAdd 实际是 App 中定义的 addTodo 函数,它接收文本并生成新任务:
ini
const addTodo = (text) => {
setTodos([...todos, {
id: Date.now(),
text,
completed: false
}]);
};
类似地,TodoList 中的复选框和删除按钮分别触发 onToggle 和 onDelete,将用户操作转化为对中心状态的更新请求。这种机制解耦了 UI 与逻辑,使组件更专注于自身职责。
兄弟组件通信:间接通过父组件协调
TodoInput、TodoList 和 TodoStats 是兄弟关系,彼此无直接引用。它们的数据同步完全依赖父组件 App 的协调:
- 当
TodoInput添加新任务,App更新todos; - 新
todos作为props传递给TodoList和TodoStats; - 二者自动重新渲染,显示最新内容。
这种"间接通信"看似绕路,实则保证了数据流的清晰与可追踪。任何状态变化都源于明确的父级更新,极大降低了调试复杂度。
本地持久化:副作用中的数据同步
为防止页面刷新丢失数据,应用需将 todos 同步至 localStorage。这属于典型的副作用操作,由 useEffect 处理:
javascript
useEffect(() => {
localStorage.setItem('todos', JSON.stringify(todos));
}, [todos]);
每当 todos 发生变化(依赖项 [todos] 触发),该副作用自动执行,将最新状态写入存储。这种声明式写法将持久化逻辑与业务逻辑分离,保持主渲染路径的纯净。
样式与用户体验:Stylus 与条件渲染
项目采用 Stylus 预处理器编写样式,配合 React 的条件类名实现动态 UI:
ini
<li className={todo.completed ? 'completed' : ''}>
当任务完成时,添加 completed 类,应用删除线等视觉反馈。同时,TodoStats 仅在存在已完成项时显示"清除"按钮:
css
{completed > 0 && <button onClick={onClearCompleted}>Clear Completed</button>}
这种细粒度的控制提升了界面的响应性与友好度。
总结
这个 Todo 应用虽功能简单,却完整体现了 React 的核心思想:组件化、单向数据流、状态集中管理与副作用隔离 。通过将状态置于顶层、通过 Props 传递数据与回调、利用 useEffect 处理持久化,代码结构清晰、逻辑内聚、易于扩展。无论是初学者理解 React 原理,还是团队建立开发规范,此类实践都提供了坚实的基础。掌握这些模式,便能在更复杂的业务场景中游刃有余地构建健壮、可维护的前端应用。