实现一个TodoList | 青训营 x 豆包MarsCode技术训练营

思路

1. 确定功能需求

  • 首先明确要实现一个简单的任务管理功能,具体包括:

    • 能够添加新任务。
    • 可以标记任务为已完成状态(并在界面上有相应显示)。
    • 能够删除不再需要的任务。

2. 选择技术框架及相关工具

  • 基于 React 框架来开发,因为 React 提供了方便的组件化开发模式以及状态管理机制,适合构建这样的交互式 UI 应用。
  • 选用 useState 钩子函数来处理组件内的状态管理,它能让函数组件轻松拥有类似类组件中 state 的功能。

3. 状态设计

  • 考虑到需要管理任务列表以及当前正在输入的新任务内容,确定了以下两个状态变量:

    • tasks:用于存储所有任务的数组,每个任务对象包含任务的文本内容(text)和完成状态(completed)两个属性。初始化为空数组,因为一开始没有任务。
    • task:用来保存用户在输入框中输入的新任务文本,初始化为空字符串。

4. 输入框及添加任务功能实现

  • 创建一个文本输入框 <input>

    • 通过 value={task}onChange={onChange} 实现输入框与 task 状态的双向绑定,确保输入框能实时反映 task 状态的变化,并且用户输入能更新 task 状态。
  • 编写 addTask 函数来实现添加任务功能:

    • 先检查 task 状态的值是否为空字符串(经过 trim 去除前后空格),只有非空时才进行添加操作,保证添加有意义的任务。
    • 通过 setTasks([...tasks, { text: task, completed: false }]) 利用数组展开运算符复制原 tasks 数组并添加新任务对象到末尾,新任务对象的 text 取自当前 task 状态,completed 初始设为 false
    • 最后将 task 状态重置为空字符串,方便用户输入下一个任务。

5. 完成任务状态切换功能实现

  • 设计 finishTask 函数来处理任务完成状态的切换:

    • 函数接收任务在 tasks 数组中的索引作为参数。
    • 先通过 const newTasks = [...tasks]; 复制一份当前的 tasks 数组到 newTasks
    • 然后根据传入的索引找到对应任务对象并将其 completed 属性取反,实现状态切换。
    • 最后通过 setTasks(newTasks) 更新 tasks 状态,使组件重新渲染以展示任务完成状态的变化。

6. 删除任务功能实现

  • 编写 deleteTask 函数用于删除任务:

    • 同样接收任务在 tasks 数组中的索引作为参数。
    • 利用 setTasks(tasks.filter((_, i) => i!== index)) 通过 filter 函数对原 tasks 数组进行过滤,保留索引不等于传入参数 index 的任务,从而实现删除指定索引任务的目的。

7. 界面渲染

  • 在组件的返回值部分,按照以下逻辑构建 UI 界面:

    • 先放置输入框和添加任务的按钮,方便用户输入新任务并添加。

    • 接着通过 tasks.map 遍历 tasks 数组,为每个任务创建一个列表项 <li>

      • 为列表项设置唯一的 key 属性,便于 React 正确识别和更新列表项。
      • 根据任务的完成状态设置列表项的文本装饰样式(完成则添加删除线)。
      • 在列表项内显示任务文本,并放置切换完成状态和删除任务的按钮,分别绑定对应的 finishTaskdeleteTask 函数及相应索引

实现过程

1. 组件定义及状态初始化

jsx 复制代码
export default function App() {
    const [tasks, setTasks] = useState([]);
    const [task, setTask] = useState('');

    //... 其他代码
}
  • 定义了一个名为 App 的函数组件,这是 React 应用中常见的组件定义方式。

  • 使用 useState 初始化了两个状态变量:

    • tasks:它是一个数组,用于存储所有的任务对象。初始值被设置为空数组 [],表示一开始没有任何任务。
    • task:它是一个字符串类型的状态变量,用于存储用户在输入框中输入的新任务内容。初始值为空字符串 ''

2. 处理输入框值变化的函数

jsx 复制代码
const onChange = e => setTask(e.target.value);

这是一个处理输入框 onChange 事件的函数。当用户在输入框中输入内容时,该函数会被触发。它通过 setTask 函数将输入框的当前值更新到 task 状态变量中,从而实现了输入框内容与 task 状态的双向绑定。

3. 添加任务的函数

jsx 复制代码
const addTask = () => {
    if (task.trim()) {
        setTasks([...tasks, { text: task, completed: false }]);
        setTask('');
    }
};
  • addTask 函数用于将新任务添加到 tasks 列表中。

  • 首先,通过 task.trim() 检查用户输入的任务内容是否为空字符串(去除前后空格后)。如果不为空:

    • 使用 setTasks 函数来更新 tasks 状态。它通过展开运算符 ... 将原有的 tasks 数组内容复制一份,并添加一个新的任务对象到数组末尾。新任务对象包含两个属性:text 属性的值取自当前 task 状态变量的值,completed 属性初始值被设置为 false,表示任务尚未完成。
    • 最后,将 task 状态变量重置为空字符串 '',以便用户可以输入下一个新任务。

4. 完成任务切换状态的函数

jsx 复制代码
const finishTask = (index) => {
    const newTasks = [...tasks];
    newTasks[index].completed =!newTasks[index].completed;
    setTasks(newTasks);
};
  • finishTask 函数用于切换指定任务的完成状态。
  • 函数接收一个参数 index,表示要切换完成状态的任务在 tasks 数组中的索引位置。
  • 首先,通过展开运算符复制一份当前的 tasks 数组到 newTasks 变量中。
  • 然后,根据传入的索引 index,找到对应的任务对象,并将其 completed 属性的值取反,从而实现任务完成状态的切换。
  • 最后,使用 setTasks 函数将更新后的 newTasks 数组设置为新的 tasks 状态,这会导致组件重新渲染,以反映任务完成状态的变化。

5. 删除任务的函数

jsx 复制代码
const deleteTask = index => setTasks(tasks.filter((_, i) => i!== index));
  • deleteTask 函数用于从 tasks 数组中删除指定索引的任务。
  • 函数接收一个参数 index,表示要删除的任务在 tasks 数组中的索引位置。
  • 通过 tasks.filter((_, i) => i!== index) 对原有的 tasks 数组进行过滤操作。filter 方法会遍历数组中的每个元素,对于索引不等于传入的 index 的元素,会被保留在新的数组中,从而实现了删除指定索引任务的目的。
  • 最后,使用 setTasks 函数将过滤后的新数组设置为新的 tasks 状态,使得组件重新渲染时不再显示已删除的任务。

6. 组件的渲染部分

jsx 复制代码
return (
    <div>
        <input
            type="text"
            value={task}
            onChange={onChange}
            placeholder="Add a new task..."
        />
        <button onClick={addTask}>Add</button>
        <ul>
            {tasks.map((item, index) => (
                <li key={index} style={{ textDecoration: item.completed? 'line-through' : 'none' }}>
                    {item.text}
                    <button onClick={() => finishTask(index)}>Toggle</button>
                    <button onClick={() => deleteTask(index)}>Delete</button>
                </li>
            ))}
        </ul>
    </div>
);
  • 在组件的 return 语句中,定义了组件的 UI 结构。

  • 首先,有一个输入框 <input>

    • type="text" 表示这是一个文本输入框。
    • value={task} 将输入框的值与 task 状态变量进行绑定,确保输入框显示的内容始终与 task 状态一致。
    • onChange={onChange} 绑定了输入框的 onChange 事件处理函数,当输入框内容改变时,会触发 onChange 函数来更新 task 状态。
    • placeholder="Add a new task..." 设置了输入框的占位符文本,提示用户输入新任务。
  • 接着,有一个按钮 <button>

    • onClick={addTask} 绑定了点击事件处理函数,当用户点击该按钮时,会触发 addTask 函数来添加新任务到 tasks 列表中。
  • 然后,通过 tasks.map 方法遍历 tasks 数组中的每个任务对象:

    • 对于每个任务对象,创建一个 <li> 列表项元素。

    • key={index} 为每个列表项设置了一个唯一的 key 属性,这是 React 在渲染列表时要求的,用于提高渲染性能和正确识别列表项的更新。

    • 根据任务对象的 completed 属性值来设置列表项的文本装饰样式。如果 completedtrue,则 textDecoration 设置为 line-through,表示任务已完成并添加删除线效果;如果为 false,则设置为 none,表示任务未完成。

    • 在列表项内部,显示任务的文本内容 {item.text}

    • 还有两个按钮:

      • 一个按钮的 onClick 绑定了 finishTask 函数,并传入当前任务的索引 index,用于切换任务的完成状态。
      • 另一个按钮的 onClick 绑定了 deleteTask 希望对你有所帮助。函数,并传入当前任务的索引 index,用于删除当前任务。

7. 实现截图

相关推荐
用户9105973027705 分钟前
CSS详解| 豆包MarsCode AI刷题
青训营笔记
huyck11 分钟前
伴学笔记1|豆包MarsCode AI 刷题
青训营笔记
幻65 天前
小U的相似字符串 | 豆包MarsCode AI刷题
青训营笔记
Grin25 天前
寻找最大葫芦 | 豆包MarsCode AI刷题
青训营笔记
用户7337855092591 个月前
后端笔记 | go语言进阶与依赖管理
青训营笔记
用户705615332611 个月前
刷题心得(三)| 豆包MarsCode AI刷题
青训营笔记
Damony1 个月前
Chain of Thought(CoT)和Tree of Thoughts(ToT)| 豆包MarsCode AI刷题
青训营笔记
Find5 个月前
MaxKB 集成langchain + Vue + PostgreSQL 的 本地大模型+本地知识库 构建私有大模型 | MarsCode AI刷题
青训营笔记
理tan王子5 个月前
伴学笔记 AI刷题 14.数组元素之和最小化 | 豆包MarsCode AI刷题
青训营笔记