React 组件开发
难度:⭐⭐ 进阶 | 预计时间:1.5 小时
React 组件开发是 Vibecoding 最常见的场景之一。这个教程带你用 Trae 做一个完整的待办事项应用,同时学会怎么 review 和迭代 AI 生成的 React 代码。
准备
bash
npx create-react-app todo-app --template typescript
cd todo-app
npm start第一步:生成 TodoList 组件
在 Trae 里描述:
创建一个 TodoList 组件,用 TypeScript:
- 显示任务列表,每项有标题和完成状态
- 顶部有输入框和按钮,支持回车提交
- 点击任务标题切换完成状态,完成的加删除线
- 每项右侧有删除按钮
- 所有状态放在组件内,不需要 Redux把生成的代码放到 src/components/TodoList.tsx,在 App.tsx 里引入跑起来。
跑起来之前先读一遍代码,特别关注 useState 里存了什么结构、每个事件处理函数在做什么。有不明白的地方就问。
第二步:拆分子组件
整个功能在一个组件里能跑,但随着功能增加会越来越难维护。让 Trae 帮你拆:
把 TodoList 拆成三个组件:
- TodoInput — 只负责输入框,通过 onAdd 回调传出新任务标题
- TodoItem — 只负责单条任务的展示,通过 onToggle 和 onDelete 回调通信
- TodoList — 组合上面两个,管理任务数组的状态拆完之后比较前后的代码结构,理解单向数据流是怎么工作的。
第三步:加持久化
刷新页面后任务丢失,加上 localStorage:
给 TodoList 加 localStorage 持久化:
- 初始化时从 localStorage 读取任务列表,读取失败时用空数组
- 每次任务列表变化时自动保存
- 用 useEffect 处理这两个副作用完整代码参考
tsx
import React, { useState } from 'react';
interface Task {
id: number;
title: string;
completed: boolean;
}
export const TodoList: React.FC = () => {
const [tasks, setTasks] = useState<Task[]>([]);
const [input, setInput] = useState('');
const addTask = () => {
if (!input.trim()) return;
setTasks([...tasks, { id: Date.now(), title: input, completed: false }]);
setInput('');
};
const toggleTask = (id: number) => {
setTasks(tasks.map(t => t.id === id ? { ...t, completed: !t.completed } : t));
};
const deleteTask = (id: number) => {
setTasks(tasks.filter(t => t.id !== id));
};
return (
<div>
<input
value={input}
onChange={e => setInput(e.target.value)}
onKeyDown={e => e.key === 'Enter' && addTask()}
placeholder="新任务..."
/>
<button onClick={addTask}>添加</button>
<ul>
{tasks.map(task => (
<li key={task.id}>
<span
onClick={() => toggleTask(task.id)}
style={{ textDecoration: task.completed ? 'line-through' : 'none', cursor: 'pointer' }}
>
{task.title}
</span>
<button onClick={() => deleteTask(task.id)}>删除</button>
</li>
))}
</ul>
</div>
);
};