本章属于 React 教程的核心路线。建议先通读概念模型,再手写最小示例,最后用练习验证自己能否独立复现。
本章目标
本章用任务管理小应用收束整套 React 教程:Task、TaskForm、TaskList、localStorage、组件拆分、表单、Effect、自定义 Hook 与测试。
阅读本章时,请把每个 API 放回“数据如何变成界面、用户操作如何改变数据”的主线中理解。React 的学习重点不是背诵语法,而是建立可预测的渲染模型。
- 识别本章概念在真实组件中的位置
- 能写出一个最小可运行示例
- 能解释常见错误为什么发生
概念模型
综合项目的关键不是功能堆叠,而是把状态放在合适层级:App 管理任务数组,TaskForm 负责新增输入,TaskList 负责展示和事件回传。
你可以把 React 程序看成一棵由组件组成的元素树。每次输入数据、状态或外部系统发生变化,React 会重新计算需要展示的 React element,再用高效的方式更新浏览器中的 DOM。
最小示例
下面示例展示组件拆分后的核心结构。完成后可以继续阅读 Next.js 教程,把客户端应用扩展到路由和服务端渲染场景。
type Task = { id: string; title: string; done: boolean };
function TaskForm({ onAdd }: { onAdd: (title: string) => void }) {
const [title, setTitle] = useState("");
return (
<form
onSubmit={(event) => {
event.preventDefault();
onAdd(title);
setTitle("");
}}
>
<input value={title} onChange={(event) => setTitle(event.target.value)} />
<button type="submit">添加</button>
</form>
);
}
function TaskList({ tasks }: { tasks: Task[] }) {
return <ul>{tasks.map((task) => <li key={task.id}>{task.title}</li>)}</ul>;
}
export function TaskApp() {
const [tasks, setTasks] = useLocalStorage<Task[]>("tasks", []);
return (
<>
<TaskForm onAdd={(title) => setTasks([...tasks, { id: crypto.randomUUID(), title, done: false }])} />
<TaskList tasks={tasks} />
</>
);
}
type LessonNote = { title: string; done: boolean };\nconst note: LessonNote = { title: 'React 教程', done: false };
规则与陷阱
规则的价值在于让多人维护同一个项目时仍能预测行为。下面这些限制看似细碎,实际都在保护组件的输入、输出和生命周期边界。
- Task 类型应作为共享契约,避免各组件重复定义不一致字段。
- TaskForm 不应直接修改列表,它只通过回调报告新增意图。
- localStorage 同步适合放进自定义 Hook,避免污染组件主体。
- 继续阅读 Next.js 教程前,先确认客户端 React 基础已经能独立完成。
练习
练习应当先小后大:先验证一个概念,再把它接入完整页面。不要在没有理解失败原因时复制更复杂的代码。
- 实现 Task、TaskForm、TaskList 三个单元。
- 用 localStorage 保存任务列表。
- 为新增任务和切换完成状态写一条测试。