前端青训营笔记 React Todo List实战 | 豆包MarsCode AI刷题

218 阅读5分钟

引言

待办事项列表(To-Do List)是一个经典的前端练习项目,可以很好地帮助开发者理解和应用 React 的核心概念。它不仅涵盖了状态管理、事件处理等基础知识,还能让开发者体会到组件化设计的优势。在本次实践中,我将逐步实现一个具备 添加编辑删除 功能的待办事项列表。为了更贴近实际需求,我还会结合自己的理解,分享一些设计和实现过程中的思考。


设计思路

在正式编码前,我们需要对功能需求和设计架构进行清晰的规划,确保代码逻辑简洁、易维护。

1. 确定功能需求

待办事项列表的核心功能包括:

  • 添加新任务:用户可以输入待办事项的内容并点击按钮将其加入列表。
  • 编辑任务:允许用户修改已经添加的待办事项内容。
  • 删除任务:用户可以移除已完成或不再需要的事项。

这些功能覆盖了用户管理待办事项的基本需求,是一个功能完整的小应用。


2. 分解功能模块

React 鼓励开发者将页面划分为多个功能单一的组件。这种组件化设计能使代码更加清晰,同时提升复用性。按照功能需求,将项目拆解为以下主要组件:

  1. App组件

    • 作为应用的入口,负责状态管理和功能逻辑的调度。
  2. TodoForm组件

    • 提供用户输入的表单,用于添加和编辑待办事项。
  3. TodoList组件

    • 用于展示所有待办事项的列表。
  4. TodoItem组件

    • 用于展示单个待办事项及其操作按钮(如编辑、删除)。

3. 确定数据结构

为了便于管理和操作,每个待办事项可以设计成一个对象,包含以下属性:

const todo = {
    id: 1,            // 唯一标识符
    text: "学习React", // 待办事项内容
    completed: false  // 是否完成
};

所有的待办事项会存储在一个数组中,应用状态的更新操作将基于此数组进行。


4. 交互流程设计

  • 添加任务:在输入框中输入任务内容,点击“添加”按钮,输入的内容会追加到待办列表。
  • 编辑任务:点击某任务旁边的“编辑”按钮,触发输入框内容的替换,修改后点击保存。
  • 删除任务:点击“删除”按钮,即可移除对应任务。

基于此设计,我们可以清晰地描绘应用的交互路径。


实现步骤

1. 初始化项目

通过 Vite 快速搭建 React 项目:

npm create vite@latest todo-app --template react
cd todo-app
npm install

启动开发服务器:

npm run dev

2. 编写基础结构

App.jsx 是应用的主组件,管理待办事项数组的状态,并通过 props 将功能传递给子组件。

import React, { useState } from "react";
import TodoForm from "./TodoForm";
import TodoList from "./TodoList";

function App() {
    const [todos, setTodos] = useState([]);

    // 添加任务
    const addTodo = (text) => {
        const newTodo = { id: Date.now(), text, completed: false };
        setTodos([...todos, newTodo]);
    };

    // 编辑任务
    const editTodo = (id, newText) => {
        const updatedTodos = todos.map(todo =>
            todo.id === id ? { ...todo, text: newText } : todo
        );
        setTodos(updatedTodos);
    };

    // 删除任务
    const deleteTodo = (id) => {
        setTodos(todos.filter(todo => todo.id !== id));
    };

    return (
        <div>
            <h1>待办事项列表</h1>
            <TodoForm onAdd={addTodo} />
            <TodoList todos={todos} onEdit={editTodo} onDelete={deleteTodo} />
        </div>
    );
}

export default App;

3. 添加TodoForm组件

TodoForm 组件负责处理用户输入的新任务内容,并通过 props 调用父组件的添加逻辑。

import React, { useState } from "react";

function TodoForm({ onAdd }) {
    const [input, setInput] = useState("");

    const handleSubmit = (e) => {
        e.preventDefault();
        if (input.trim()) {
            onAdd(input); // 调用父组件传递的添加方法
            setInput(""); // 清空输入框
        }
    };

    return (
        <form onSubmit={handleSubmit}>
            <input
                type="text"
                value={input}
                onChange={(e) => setInput(e.target.value)}
                placeholder="添加新的待办事项"
            />
            <button type="submit">添加</button>
        </form>
    );
}

export default TodoForm;

4. 编写TodoList和TodoItem组件

TodoList 组件接收 todos 数据并渲染子组件 TodoItem

import React from "react";
import TodoItem from "./TodoItem";

function TodoList({ todos, onEdit, onDelete }) {
    return (
        <ul>
            {todos.map(todo => (
                <TodoItem
                    key={todo.id}
                    todo={todo}
                    onEdit={onEdit}
                    onDelete={onDelete}
                />
            ))}
        </ul>
    );
}

export default TodoList;

TodoItem 组件负责展示单个任务的内容,并处理编辑和删除操作:

import React, { useState } from "react";

function TodoItem({ todo, onEdit, onDelete }) {
    const [isEditing, setIsEditing] = useState(false);
    const [newText, setNewText] = useState(todo.text);

    const handleEdit = () => {
        setIsEditing(true);
    };

    const handleSave = () => {
        onEdit(todo.id, newText);
        setIsEditing(false);
    };

    return (
        <li>
            {isEditing ? (
                <>
                    <input
                        type="text"
                        value={newText}
                        onChange={(e) => setNewText(e.target.value)}
                    />
                    <button onClick={handleSave}>保存</button>
                </>
            ) : (
                <>
                    <span>{todo.text}</span>
                    <button onClick={handleEdit}>编辑</button>
                </>
            )}
            <button onClick={() => onDelete(todo.id)}>删除</button>
        </li>
    );
}

export default TodoItem;

结果展示

  1. 添加待办

image.png

  1. 编辑待办

image.png

  1. 删除待办

image.png

个人思考

  1. 关于组件化
    将代码划分为多个小型组件后,每个组件的职责单一且明确,这样不仅易于调试,还方便功能扩展。例如,如果我们未来想加入任务完成状态的功能,只需在 TodoItem 中调整。

  2. 状态管理的局限性
    当前我们用 useState 管理应用状态,这种方式适合小型项目。若状态变得复杂或需要跨组件共享,推荐使用 Context 或 Redux 进行全局状态管理。

  3. 用户体验优化

    • 可以增加本地存储功能(如 localStorage),让用户刷新页面后仍能保留数据。
    • 增加任务完成标记功能,用户可以一目了然地看到哪些任务已完成。
    • 提供更美观的样式或动画,增强用户的交互体验。

结语

通过这个项目,我们熟悉了 React 的基本操作,同时深刻体会到组件化和状态管理的重要性。未来的改进方向可以包括更复杂的功能逻辑或与后端联通,构建一个功能更完善的任务管理工具。