使用 React 实现一个简单的待办事项列表 | 豆包MarsCode AI刷题
在前端开发中,待办事项列表(Todo List)是一个经典的入门项目。通过实现这个项目,我们可以很好地理解 React 的核心概念,如组件、状态管理、事件处理等。本文将详细介绍如何使用 React 实现一个具有添加、编辑和删除功能的待办事项列表。
项目需求分析
在开始编码之前,让我们先明确项目的具体需求:
- 用户可以添加新的待办事项
- 用户可以标记待办事项为已完成状态
- 用户可以编辑现有的待办事项
- 用户可以删除待办事项
- 所有待办事项需要持久化存储在本地
技术选型
本项目将使用以下技术栈:
- React 18
- TypeScript
- CSS Module
- localStorage 用于数据持久化
核心代码实现
首先,我们需要定义待办事项的接口:
interface Todo {
id: number;
text: string;
completed: boolean;
}
然后,实现主要的 TodoList 组件:
import React, { useState, useEffect } from 'react';
import styles from './TodoList.module.css';
const TodoList: React.FC = () => {
const [todos, setTodos] = useState<Todo[]>([]);
const [input, setInput] = useState('');
const [editId, setEditId] = useState<number | null>(null);
// 从 localStorage 加载数据
useEffect(() => {
const savedTodos = localStorage.getItem('todos');
if (savedTodos) {
setTodos(JSON.parse(savedTodos));
}
}, []);
// 保存数据到 localStorage
useEffect(() => {
localStorage.setItem('todos', JSON.stringify(todos));
}, [todos]);
// 添加待办事项
const handleAdd = () => {
if (!input.trim()) return;
const newTodo: Todo = {
id: Date.now(),
text: input,
completed: false
};
setTodos([...todos, newTodo]);
setInput('');
};
// 切换完成状态
const toggleComplete = (id: number) => {
setTodos(todos.map(todo =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
));
};
// 删除待办事项
const handleDelete = (id: number) => {
setTodos(todos.filter(todo => todo.id !== id));
};
// 编辑待办事项
const handleEdit = (id: number, newText: string) => {
setTodos(todos.map(todo =>
todo.id === id ? { ...todo, text: newText } : todo
));
setEditId(null);
};
return (
<div className={styles.container}>
<h1>待办事项列表</h1>
<div className={styles.inputContainer}>
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="添加新的待办事项"
/>
<button onClick={handleAdd}>添加</button>
</div>
<ul className={styles.todoList}>
{todos.map(todo => (
<li key={todo.id} className={`${styles.todoItem} ${todo.completed ? styles.completed : ''}`}>
{editId === todo.id ? (
<input
type="text"
value={todo.text}
onChange={(e) => handleEdit(todo.id, e.target.value)}
onBlur={() => setEditId(null)}
autoFocus
/>
) : (
<>
<input
type="checkbox"
checked={todo.completed}
onChange={() => toggleComplete(todo.id)}
/>
<span onDoubleClick={() => setEditId(todo.id)}>{todo.text}</span>
<button onClick={() => handleDelete(todo.id)}>删除</button>
</>
)}
</li>
))}
</ul>
</div>
);
};
export default TodoList;
为了让我们的待办事项列表看起来更加美观,我们还需要添加一些样式:
.container {
max-width: 600px;
margin: 0 auto;
padding: 20px;
}
.inputContainer {
display: flex;
gap: 10px;
margin-bottom: 20px;
}
.inputContainer input {
flex: 1;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
}
.inputContainer button {
padding: 8px 16px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.todoList {
list-style: none;
padding: 0;
}
.todoItem {
display: flex;
align-items: center;
gap: 10px;
padding: 10px;
border-bottom: 1px solid #eee;
}
.completed span {
text-decoration: line-through;
color: #888;
}
实现要点解析
-
状态管理:
- 使用
useState管理待办事项列表、输入框内容和编辑状态 - 使用
useEffect实现数据的持久化存储
- 使用
-
功能实现:
- 添加:通过输入框和添加按钮实现
- 编辑:双击文本触发编辑状态
- 删除:点击删除按钮移除项目
- 完成状态:通过复选框切换
-
数据持久化:
- 使用 localStorage 在页面刷新后保持数据
- 每次数据更新时自动保存
性能优化考虑
- 使用
key属性优化列表渲染 - 避免不必要的重渲染
- 使用防抖处理输入事件(可选优化)
项目扩展思考
- 添加分类功能
- 实现拖拽排序
- 添加截止日期
- 支持多用户
- 添加数据同步功能
总结
通过实现这个简单的待办事项列表,我们不仅掌握了 React 的基础知识,还学习了如何组织代码结构、管理状态以及处理用户交互。这个项目虽然简单,但包含了前端开发中的许多重要概念,是一个很好的学习案例。
在实际开发中,我们可能还需要考虑更多因素,比如:
- 错误处理
- 加载状态
- 表单验证
- 响应式设计
- 无障碍访问