使用React 实现一个简单的待办事项列表 | 青训营

85 阅读5分钟

需求:使用React 实现一个简单的待办事项列表 ,用户可以添加、编辑和删除待办事项。

面对需求,让我们类比一下番茄TODO,首先用户需要一个输入框和提交按钮来添加待办事项。那添加完以后,如果用户想要修改一下这个事项的细节,需要一个“编辑”按钮,新修改的内容需要写在刚刚那个输入框中。同理,当用户完成了这个待办事项以后,需要通过“删除”按钮来把这个事项删去。这里需要注意的是,由于我们只是简单实现这个待办事项,只需要一个输入框,一个提交按钮,以及多个编辑按钮。用户就是在输入框里输东西,然后如果是添加就点提交,如果是编辑就点已有的待办事项组件中渲染出的“编辑”按钮。

理清思路后,不难想到可以使用React中的useState钩子来创建状态管理待办事项,还可以使用map函数来遍历待办事项列表状态,方便一一渲染单个待办事项组件。那么第一步就是import:

import React, { useState } from 'react';

接着我们需要使用状态来管理待办事项列表。

const [todos, setTodos] = useState([]);

使用状态来管理当前正在编辑的待办事项:当用户未点击“编辑”按钮时的状态统一为-1,点击时则不等于-1,以此区分编辑与否的状态。

const [editIndex, setEditIndex] = useState(-1);

使用状态来管理添加/编辑表单的输入。

const [newTodoText, setNewTodoText] = useState("");

定义完状态以后,首先实现添加事项:

const addTodo = () => {
  // 检查新待办事项文本是否非空
  if (newTodoText.trim() !== '') {
    // 如果没有正在编辑的事项,也就是没点击“编辑”按钮
    if (editIndex === -1) {
      // 添加新待办事项到待办事项列表中
      setTodos([...todos, newTodoText]);
    } else {
      // 如果正在编辑事项(点击了),则复制待办事项列表
      const updatedTodos = [...todos];
      // 更新正在编辑的事项的文本
      updatedTodos[editIndex] = newTodoText;
      // 用更新后的待办事项列表更新状态
      setTodos(updatedTodos);
      // 结束编辑模式
      setEditIndex(-1);
    }
    // 清空新待办事项输入框
    setNewTodoText('');
  }
};

Tips:

  • .trim()是一个字符串方法,用于删除字符串的两端空白字符(如空格、制表符、换行等)。
  • setTodos([...todos, newTodoText])中的省略号是扩展运算符,表示包含了原始的待办事项数组 todos 中的所有元素。具体来说,[...todos, newTodoText] 表示在原始 todos 数组的基础上创建一个新数组,新数组包含了原始数组中的所有元素以及 newTodoText 字符串。 这个新数组将被传递给 setTodos 函数,用于更新待办事项列表的状态。

编辑待办事项:

// 定义一个用于编辑待办事项的函数,参数是需要编辑的事项的索引
const editTodo = (index) => {
  // 设置输入框的文本为待编辑事项的文本
  setNewTodoText(todos[index]);
  // 设置编辑索引为当前待编辑事项的索引
  setEditIndex(index);
};

删除待办事项:

// 定义一个用于删除待办事项的函数,参数是待删除事项的索引
const deleteTodo = (index) => {
  // 使用 filter 方法创建一个新数组,其中不包含指定索引的待办事项
  const updatedTodos = todos.filter((_, i) => i !== index);
  // 使用 setTodos 更新待办事项列表状态为新的数组
  setTodos(updatedTodos);
};

Tips:

  • filter((_, i) => i !== index)的作用是创建一个新数组updatedTodos,其中包含了除了索引为index的待办事项之外的所有其他待办事项。

然后把输入框,按钮什么的加上:

    <div>
      <h1>Todo List</h1>
      <div>
        {/* 输入框用于添加/编辑待办事项 */}
        <input
          type="text"
          value={newTodoText}
          onChange={(e) => setNewTodoText(e.target.value)}
        />
        <button onClick={addTodo}>
          {editIndex === -1 ? 'Add' : 'Update'}
        </button>
      </div>
      <ul>
        {/* 渲染待办事项列表 */}
        {todos.map((todo, index) => (
          <li key={index}>
            {todo}
            <button onClick={() => editTodo(index)}>Edit</button>
            <button onClick={() => deleteTodo(index)}>Delete</button>
          </li>
        ))}
      </ul>
    </div>

Tips:

  • onChange={(e) => setNewTodoText(e.target.value)}是在输入框的值改变时触发的事件处理函数。当用户在输入框中键入或修改文本时,事件对象 e 包含了输入框的状态。e.target.value 表示当前输入框中的文本值。这个值会传递给 setNewTodoText 函数,从而更新状态中的 newTodoText,以反映用户在输入框中键入或修改的文本。
  • todos.map((todo, index) => (是一个使用 map 方法的调用,用于遍历 todos 数组中的每个元素。todo是遍历中当前的待办事项。在每次迭代中,todo 变量会被设置为数组中的一个待办事项。index是遍历中当前待办事项的索引。

最后,完整代码如下:

import React, { useState } from 'react';

function App() {
  const [todos, setTodos] = useState([]);
  
  const [editIndex, setEditIndex] = useState(-1);
  
  const [newTodoText, setNewTodoText] = useState('');

  const addTodo = () => {
    if (newTodoText.trim() !== '') {
      if (editIndex === -1) {
        setTodos([...todos, newTodoText]);
      } else {
        const updatedTodos = [...todos];
        updatedTodos[editIndex] = newTodoText;
        setTodos(updatedTodos);
        setEditIndex(-1);
      }
      setNewTodoText('');
    }
  };

  const editTodo = (index) => {
    setNewTodoText(todos[index]);
    setEditIndex(index);
  };

  const deleteTodo = (index) => {
    const updatedTodos = todos.filter((_, i) => i !== index);
    setTodos(updatedTodos);
  };

  return (
    <div>
      <h1>Todo List</h1>
      <div>
        <input
          type="text"
          value={newTodoText}
          onChange={(e) => setNewTodoText(e.target.value)}
        />
        <button onClick={addTodo}>
          {editIndex === -1 ? 'Add' : 'Update'}
        </button>
      </div>
      <ul>
        {todos.map((todo, index) => (
          <li key={index}>
            {todo}
            <button onClick={() => editTodo(index)}>Edit</button>
            <button onClick={() => deleteTodo(index)}>Delete</button>
          </li>
        ))}
      </ul>
    </div>
  );
}

export default App;

至此我们就用React实现了一个简单的待办事项列表,它拥有基本的添加,编辑,删除功能。后期可以加入CSS样式美化一下。但是它也存在很多不足,比如不能对比输入框内的内容和已有的待办事项内容,这样可能会重复添加内容相同的待办事项;也没有日期的选择,只能靠用户手动输入;没有排序功能...这些问题还需要进一步学习和改进。