需求:使用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样式美化一下。但是它也存在很多不足,比如不能对比输入框内的内容和已有的待办事项内容,这样可能会重复添加内容相同的待办事项;也没有日期的选择,只能靠用户手动输入;没有排序功能...这些问题还需要进一步学习和改进。