使用React实现一个简单的待办事项列表
目录
-
介绍
- 目的和背景
- 技术栈
- 项目概述
-
环境设置
- 安装Node.js和npm
- 创建React应用程序
-
组件结构
- 主应用程序组件
- 待办事项列表组件
- 待办事项单独显示组件
-
状态管理
- 使用
useState管理待办事项列表 - 使用状态来处理编辑状态
- 使用
-
添加待办事项
- 创建输入框组件
- 通过事件处理函数添加待办事项
-
展示待办事项
- 显示待办事项列表
- 显示单个待办事项的组件
-
删除待办事项
- 为每个待办事项添加删除按钮
- 实现删除待办事项的事件处理
-
编辑待办事项
- 为每个待办事项添加编辑按钮
- 使用状态管理编辑状态
- 更新待办事项文本
-
样式化
- 使用CSS或样式库为应用程序添加样式
- 样式化待办事项列表和单独事项
-
交互性改进
- 使用按键事件处理添加和编辑待办事项
- 在编辑状态下按Enter保存编辑
-
总结与未来的改进
- 回顾项目的功能和实现
- 可能的改进方向,如持久化存储、更多交互功能等
-
附录
- 完整的源代码示例
- 参考资料和资源链接
介绍
目的和背景
本文档旨在介绍如何使用React构建一个简单的待办事项列表应用程序。待办事项列表是一种常见的应用程序类型,用于帮助用户跟踪和管理任务。通过本文档,您将了解如何使用React组件、状态管理和事件处理等核心概念来构建一个功能完善的待办事项列表应用。
技术栈
在本项目中,我们将使用以下技术栈来开发待办事项列表应用:
- React: 一个用于构建用户界面的JavaScript库,具有高度的可重用性和组件化特性。
- JavaScript: 作为React应用的主要编程语言。
- HTML 和 CSS: 用于渲染和样式化应用程序界面。
- npm: 包管理工具,用于安装和管理项目依赖项。
项目概述
本项目旨在创建一个具有以下功能的待办事项列表应用程序:
- 添加待办事项: 用户可以在输入框中输入任务描述,按下"Enter"键即可将待办事项添加到列表中。
- 显示待办事项: 应用程序将显示所有添加的待办事项列表,每个事项显示其任务描述。
- 编辑待办事项: 用户可以编辑已添加的待办事项,修改任务描述。
- 删除待办事项: 用户可以从列表中删除不再需要的待办事项。
通过这个项目,我们将学习如何创建React组件、使用状态管理来追踪待办事项列表,以及如何处理用户的添加、编辑和删除操作。我们还将添加基本的样式来美化应用程序界面。最终,您将获得一个可以实际使用的简单待办事项列表应用。在接下来的章节中,我们将详细介绍每个步骤的实现。
环境设置
安装 Node.js 和 npm
在开始构建React待办事项列表应用程序之前,您需要确保您的计算机上已安装Node.js和npm。Node.js是一个基于Chrome V8引擎的JavaScript运行时,而npm是Node.js的包管理工具,用于安装和管理项目所需的依赖项。
-
Node.js安装: 前往 Node.js官网 下载并安装适用于您操作系统的Node.js版本。
-
npm版本检查: 安装完成后,您可以在终端(命令行界面)中运行以下命令,以确保Node.js和npm已成功安装,并查看其版本信息:
node -v npm -v
创建 React 应用程序
在您已经安装好Node.js和npm后,您可以使用create-react-app命令来创建一个新的React应用程序。create-react-app是一个官方提供的工具,可以快速设置React项目的基本结构和开发环境。
-
创建应用程序: 打开终端,进入您选择的项目文件夹,并运行以下命令来创建React应用程序:
npx create-react-app todo-list-app这将会在当前文件夹下创建一个名为
todo-list-app的新React应用程序。 -
进入项目目录: 创建应用程序完成后,进入项目目录:
cd todo-list-app -
运行应用程序: 使用以下命令启动开发服务器,以查看应用程序的初始界面:
npm start这将自动打开一个浏览器窗口,显示应用程序在开发模式下的预览。您可以通过编辑
src目录中的文件来实时查看更改效果。
通过这些步骤,您已经成功设置了一个新的React应用程序。接下来,我们将在项目中创建组件、处理状态和实现功能。请继续阅读下一个章节以了解更多细节。
组件结构
在构建React待办事项列表应用程序时,我们将使用组件来划分不同的功能单元,以便更好地组织代码并实现可重用性。以下是我们计划在项目中创建的主要组件。
1. 主应用程序组件
主应用程序组件是应用程序的核心,它将承载整个待办事项列表以及与其相关的功能。在我们的例子中,我们可以称其为App组件。这个组件将管理整个待办事项列表的状态,以及与待办事项的添加、编辑和删除等功能。
// src/App.js
import React, { useState } from 'react';
import TodoList from './TodoList';
const App = () => {
const [todos, setTodos] = useState([]);
// 添加、编辑、删除等功能的处理函数将在这里定义
return (
<div className="app">
<h1>Todo List</h1>
{/* 输入框和待办事项列表将在这里渲染 */}
</div>
);
};
export default App;
2. 待办事项列表组件
TodoList组件负责展示所有待办事项的列表。它将接收待办事项数组作为props,并将每个待办事项传递给单独的显示组件。
// src/TodoList.js
import React from 'react';
import TodoItem from './TodoItem';
const TodoList = ({ todos }) => {
return (
<div className="todo-list">
{todos.map(todo => (
<TodoItem key={todo.id} todo={todo} />
))}
</div>
);
};
export default TodoList;
3. 待办事项单独显示组件
TodoItem组件将负责单独显示每个待办事项,包括待办事项的文本、编辑和删除按钮。它将从TodoList组件接收一个待办事项对象作为props。
// src/TodoItem.js
import React from 'react';
const TodoItem = ({ todo }) => {
return (
<div className="todo-item">
<span>{todo.text}</span>
{/* 编辑和删除按钮将在这里渲染 */}
</div>
);
};
export default TodoItem;
这就是我们计划在项目中创建的主要组件结构。接下来,我们将实现添加、编辑和删除待办事项的功能,以及与这些功能相关的事件处理函数。
状态管理
在React中,状态(state)是一个非常重要的概念,用于管理组件的动态数据。在待办事项列表应用程序中,我们将使用useState钩子来管理待办事项列表和编辑状态。
使用 useState 管理待办事项列表
我们将在主应用程序组件中使用useState来管理待办事项列表的状态。首先,我们在App.js中导入useState,然后在组件内部使用它来声明一个名为todos的状态。
// src/App.js
import React, { useState } from 'react';
import TodoList from './TodoList';
const App = () => {
const [todos, setTodos] = useState([]); // 初始化待办事项列表为空数组
// 添加、编辑、删除等功能的处理函数将在这里定义
return (
<div className="app">
<h1>Todo List</h1>
{/* 输入框和待办事项列表将在这里渲染 */}
</div>
);
};
export default App;
现在,我们可以使用todos状态来存储和管理待办事项列表。每当我们更新todos状态时,React将自动重新渲染组件以反映最新的状态。
使用状态来处理编辑状态
我们还将使用状态来管理每个待办事项的编辑状态。当用户选择编辑一个待办事项时,我们将在状态中存储编辑中的待办事项的ID,并将其传递给TodoItem组件以显示相应的编辑输入框。
在App.js中,我们可以声明一个名为editTodo的状态,用于存储当前正在编辑的待办事项的ID。当用户点击编辑按钮时,我们将设置editTodo状态为相应的待办事项ID。
// src/App.js
import React, { useState } from 'react';
import TodoList from './TodoList';
const App = () => {
const [todos, setTodos] = useState([]);
const [editTodo, setEditTodo] = useState(null); // 初始化为null,表示没有待办事项处于编辑状态
// 添加、编辑、删除等功能的处理函数将在这里定义
return (
<div className="app">
<h1>Todo List</h1>
{/* 输入框和待办事项列表将在这里渲染 */}
</div>
);
};
export default App;
这将使我们能够在待办事项列表中显示编辑状态,并在保存编辑时更新相应的待办事项。在下一个章节中,我们将实现处理添加、编辑和删除操作的事件处理函数。
添加待办事项
在这一节中,我们将会实现添加待办事项的功能。我们将创建一个输入框组件,用户可以在其中输入任务描述,并通过事件处理函数将待办事项添加到列表中。
1. 创建输入框组件
首先,让我们创建一个输入框组件,它将渲染一个文本输入框,并根据用户的输入更新组件的本地状态。我们将称其为TodoInput组件。
// src/TodoInput.js
import React, { useState } from 'react';
const TodoInput = ({ onAdd }) => {
const [text, setText] = useState('');
const handleKeyDown = event => {
if (event.key === 'Enter' && text.trim() !== '') {
onAdd(text);
setText('');
}
};
return (
<input
type="text"
placeholder="添加待办事项"
value={text}
onChange={e => setText(e.target.value)}
onKeyDown={handleKeyDown}
/>
);
};
export default TodoInput;
2. 通过事件处理函数添加待办事项
在主应用程序组件中,我们需要实现一个事件处理函数,以便将新的待办事项添加到待办事项列表中。在App.js中,我们导入TodoInput组件,并将事件处理函数传递给它,以便在用户按下"Enter"键时添加待办事项。
// src/App.js
import React, { useState } from 'react';
import TodoList from './TodoList';
import TodoInput from './TodoInput';
const App = () => {
const [todos, setTodos] = useState([]);
const [editTodo, setEditTodo] = useState(null);
const addTodo = text => {
const newTodo = { id: Date.now(), text };
setTodos([...todos, newTodo]);
};
// 编辑和删除等功能的处理函数将在这里定义
return (
<div className="app">
<h1>Todo List</h1>
<TodoInput onAdd={addTodo} />
<TodoList todos={todos} onDelete={deleteTodo} onEdit={editTodoItem} />
{/* 编辑待办事项的输入框将在这里渲染 */}
</div>
);
};
export default App;
在上述代码中,我们通过onAdd属性将addTodo函数传递给TodoInput组件。TodoInput组件在用户按下"Enter"键时会调用onAdd函数,将用户输入的文本作为参数传递给它。addTodo函数会在待办事项列表中添加新的待办事项。
现在,当您在输入框中输入文本并按下"Enter"键时,应用程序将会添加一个新的待办事项到列表中。接下来,我们将继续实现编辑和删除待办事项的功能。
展示待办事项
在这一节中,我们将实现显示待办事项列表的功能。我们将会创建一个待办事项列表组件,以及一个用于显示单个待办事项的组件。
1. 显示待办事项列表
我们将创建一个名为TodoList的组件,用于显示待办事项列表。这个组件将接收一个待办事项数组作为props,并使用map函数来遍历数组,将每个待办事项传递给TodoItem组件以单独显示。
// src/TodoList.js
import React from 'react';
import TodoItem from './TodoItem';
const TodoList = ({ todos, onDelete, onEdit }) => {
return (
<div className="todo-list">
{todos.map(todo => (
<TodoItem
key={todo.id}
todo={todo}
onDelete={onDelete}
onEdit={onEdit}
/>
))}
</div>
);
};
export default TodoList;
2. 显示单个待办事项的组件
我们将创建一个名为TodoItem的组件,用于显示单个待办事项。这个组件将接收一个待办事项对象作为props,并根据对象中的文本来显示待办事项的内容。
// src/TodoItem.js
import React from 'react';
const TodoItem = ({ todo, onDelete, onEdit }) => {
return (
<div className="todo-item">
<span>{todo.text}</span>
<button onClick={() => onEdit(todo.id)}>编辑</button>
<button onClick={() => onDelete(todo.id)}>删除</button>
</div>
);
};
export default TodoItem;
在上述代码中,我们通过props将onDelete和onEdit函数传递给TodoItem组件,以便在用户点击删除和编辑按钮时触发相应的事件处理函数。
在主应用程序组件中,您应该已经将TodoList组件嵌套在合适的位置,从而在界面上显示待办事项列表。
现在,您应该能够在界面上看到待办事项列表,并且每个待办事项都附有删除和编辑按钮。接下来,我们将实现编辑和删除待办事项的功能。
删除待办事项
在这一节中,我们将实现删除待办事项的功能。我们将为每个待办事项添加一个删除按钮,并实现相应的事件处理函数来从待办事项列表中删除选定的事项。
1. 为每个待办事项添加删除按钮
在TodoItem组件中,我们将为每个待办事项添加一个"删除"按钮,以便用户可以点击它来删除相应的事项。
// src/TodoItem.js
import React from 'react';
const TodoItem = ({ todo, onDelete, onEdit }) => {
return (
<div className="todo-item">
<span>{todo.text}</span>
<button onClick={() => onEdit(todo.id)}>编辑</button>
<button onClick={() => onDelete(todo.id)}>删除</button>
</div>
);
};
export default TodoItem;
2. 实现删除待办事项的事件处理
在主应用程序组件中,我们需要实现一个事件处理函数,以便在用户点击"删除"按钮时从待办事项列表中删除相应的事项。在App.js中,我们将编写名为deleteTodo的函数。
// src/App.js
import React, { useState } from 'react';
import TodoList from './TodoList';
import TodoInput from './TodoInput';
const App = () => {
const [todos, setTodos] = useState([]);
const [editTodo, setEditTodo] = useState(null);
const addTodo = text => {
const newTodo = { id: Date.now(), text };
setTodos([...todos, newTodo]);
};
const deleteTodo = id => {
const updatedTodos = todos.filter(todo => todo.id !== id);
setTodos(updatedTodos);
};
// 编辑等功能的处理函数将在这里定义
return (
<div className="app">
<h1>Todo List</h1>
<TodoInput onAdd={addTodo} />
<TodoList todos={todos} onDelete={deleteTodo} onEdit={editTodoItem} />
{/* 编辑待办事项的输入框将在这里渲染 */}
</div>
);
};
export default App;
在上述代码中,deleteTodo函数接收一个待删除的待办事项ID作为参数。我们使用filter函数来创建一个新的待办事项数组,其中不包括要删除的事项。然后,我们使用setTodos来更新待办事项列表的状态。
现在,您应该能够在界面上看到每个待办事项旁边的"删除"按钮,并且当您点击该按钮时,相应的事项将从列表中删除。接下来,我们将继续实现编辑待办事项的功能。
编辑待办事项
在这一节中,我们将实现编辑待办事项的功能。我们将为每个待办事项添加一个编辑按钮,当用户点击它时,将进入编辑状态,允许用户修改待办事项的文本。
1. 为每个待办事项添加编辑按钮
在TodoItem组件中,我们将为每个待办事项添加一个"编辑"按钮,以便用户可以点击它来进入编辑状态。
// src/TodoItem.js
import React from 'react';
const TodoItem = ({ todo, onDelete, onEdit }) => {
return (
<div className="todo-item">
<span>{todo.text}</span>
<button onClick={() => onEdit(todo.id)}>编辑</button>
<button onClick={() => onDelete(todo.id)}>删除</button>
</div>
);
};
export default TodoItem;
2. 使用状态管理编辑状态
在主应用程序组件中,我们将实现一个事件处理函数,以便在用户点击"编辑"按钮时,将相应的待办事项ID存储在状态中,以表示该待办事项处于编辑状态。我们将称这个状态为editTodo。
// src/App.js
import React, { useState } from 'react';
import TodoList from './TodoList';
import TodoInput from './TodoInput';
const App = () => {
const [todos, setTodos] = useState([]);
const [editTodo, setEditTodo] = useState(null);
const addTodo = text => {
const newTodo = { id: Date.now(), text };
setTodos([...todos, newTodo]);
};
const deleteTodo = id => {
const updatedTodos = todos.filter(todo => todo.id !== id);
setTodos(updatedTodos);
};
const editTodoItem = id => {
const todoToEdit = todos.find(todo => todo.id === id);
setEditTodo(todoToEdit);
};
return (
<div className="app">
<h1>Todo List</h1>
<TodoInput onAdd={addTodo} />
<TodoList todos={todos} onDelete={deleteTodo} onEdit={editTodoItem} />
{editTodo && (
<div className="edit-todo">
{/* 编辑待办事项的输入框将在这里渲染 */}
</div>
)}
</div>
);
};
export default App;
3. 更新待办事项文本
在editTodo状态不为null时,我们将在界面上显示一个输入框,用于编辑待办事项的文本。我们将实现一个事件处理函数,当用户在编辑输入框中按下"Enter"键时,将更新相应的待办事项文本。
在App.js中,我们将在状态为editTodo时,渲染一个输入框,并使用一个新的状态来存储正在编辑的待办事项的新文本。
// src/App.js
import React, { useState } from 'react';
import TodoList from './TodoList';
import TodoInput from './TodoInput';
const App = () => {
const [todos, setTodos] = useState([]);
const [editTodo, setEditTodo] = useState(null);
const [editText, setEditText] = useState('');
const addTodo = text => {
const newTodo = { id: Date.now(), text };
setTodos([...todos, newTodo]);
};
const deleteTodo = id => {
const updatedTodos = todos.filter(todo => todo.id !== id);
setTodos(updatedTodos);
};
const editTodoItem = id => {
const todoToEdit = todos.find(todo => todo.id === id);
setEditTodo(todoToEdit);
setEditText(todoToEdit.text);
};
const saveEditTodo = id => {
const updatedTodos = todos.map(todo =>
todo.id === id ? { ...todo, text: editText } : todo
);
setTodos(updatedTodos);
setEditTodo(null);
};
return (
<div className="app">
<h1>Todo List</h1>
<TodoInput onAdd={addTodo} />
<TodoList todos={todos} onDelete={deleteTodo} onEdit={editTodoItem} />
{editTodo && (
<div className="edit-todo">
<input
type="text"
value={editText}
onChange={e => setEditText(e.target.value)}
onKeyDown={e => {
if (e.key === 'Enter' && editText.trim() !== '') {
saveEditTodo(editTodo.id);
}
}}
/>
</div>
)}
</div>
);
};
export default App;
在上述代码中,当用户按下"Enter"键时,我们调用saveEditTodo函数来更新待办事项的文本。这将使您能够编辑待办事项并保存更改。
现在,您应该已经实现了一个基本的React待办事项列表应用程序,其中包括添加、编辑和删除待办事项的功能。您可以根据需要进一步扩展和优化这个应用程序,例如添加样式、实现持久化存储等。
样式化
为了使您的待办事项列表应用程序具有更好的外观和用户体验,您可以为应用程序添加样式。您可以使用普通的CSS,也可以使用流行的CSS库,如Bootstrap、Tailwind CSS等。
以下是一个简单的示例,展示如何为待办事项列表和单独事项添加一些基本的样式。
1. 添加全局样式
您可以创建一个名为styles.css的CSS文件,并将其链接到您的React应用程序中。在这个文件中,您可以为应用程序的主要元素添加一些全局样式。
/* styles.css */
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
}
.app {
text-align: center;
padding: 20px;
}
.todo-list {
display: flex;
flex-direction: column;
align-items: flex-start;
margin-top: 20px;
}
.todo-item {
display: flex;
align-items: center;
margin-bottom: 10px;
}
.todo-item span {
margin-right: 10px;
}
.edit-todo input {
width: 100%;
padding: 5px;
border: 1px solid #ccc;
border-radius: 4px;
}
然后,在主应用程序组件中通过导入styles.css来应用这些样式。
// src/App.js
import React, { useState } from 'react';
import TodoList from './TodoList';
import TodoInput from './TodoInput';
import './styles.css'; // 导入样式文件
const App = () => {
// ...之前的代码
};
export default App;
2. 样式化待办事项列表和单独事项
在上述的CSS中,我们已经添加了一些样式规则来为待办事项列表和单独事项添加样式。例如,我们使用flex布局使待办事项在垂直方向上垂直排列,为编辑输入框添加了一些基本的边框和圆角样式。
您可以根据自己的喜好和设计需要,进一步定制这些样式。您还可以使用CSS库来快速创建美观的样式,例如引入Bootstrap来为应用程序添加现成的组件和样式。
请注意,上述示例只是一个简单的样式化示范,您可以根据您的项目需要进行更详细的样式化调整。
交互性改进
为了进一步提升用户体验,您可以添加一些交互性改进,例如使用按键事件处理来添加和编辑待办事项,以及在编辑状态下按下"Enter"键来保存编辑。
1. 使用按键事件处理添加和编辑待办事项
目前,我们已经使用了按键事件处理来实现了添加待办事项的功能。用户可以在输入框中输入任务描述,然后按下"Enter"键来添加待办事项。为了使编辑功能也具有类似的交互性,我们可以在编辑输入框中也使用按键事件处理。
在TodoItem.js中的编辑状态下,我们可以为编辑输入框添加一个onKeyDown事件处理函数,以便在用户按下"Enter"键时触发保存编辑操作。
// src/TodoItem.js
import React, { useState } from 'react';
const TodoItem = ({ todo, onDelete, onEdit }) => {
const [editText, setEditText] = useState(todo.text);
const [isEditing, setIsEditing] = useState(false);
const saveEditTodo = () => {
onEdit(todo.id, editText);
setIsEditing(false);
};
return (
<div className="todo-item">
{isEditing ? (
<input
type="text"
value={editText}
onChange={e => setEditText(e.target.value)}
onKeyDown={e => {
if (e.key === 'Enter' && editText.trim() !== '') {
saveEditTodo();
}
}}
/>
) : (
<span>{todo.text}</span>
)}
<button onClick={() => setIsEditing(!isEditing)}>
{isEditing ? '保存' : '编辑'}
</button>
<button onClick={() => onDelete(todo.id)}>删除</button>
</div>
);
};
export default TodoItem;
在上述代码中,我们为编辑按钮添加了一个onClick事件处理函数,用于切换编辑状态。当用户在编辑状态下按下"Enter"键时,我们将调用saveEditTodo函数来保存编辑。这将使用户能够通过按下"Enter"键来保存编辑,提升了编辑操作的交互性。
2. 编辑状态下按下"Enter"保存编辑
在编辑状态下按下"Enter"键保存编辑是一种常见的用户期望行为。通过添加按键事件处理函数,我们可以为编辑功能增加这种方便的交互。
在上述的示例代码中,我们使用了onKeyDown事件处理函数来检测用户按下的键。如果用户按下的是"Enter"键,并且编辑文本不为空,则调用saveEditTodo函数来保存编辑。这样,用户就可以在编辑状态下直接按下"Enter"键来保存编辑的待办事项文本。
通过这些交互性改进,您可以提升您的待办事项列表应用程序的用户体验,并使用户能够更快速和方便地进行添加和编辑操作。
总结与未来的改进
在本项目中,我们成功地创建了一个基本的React待办事项列表应用程序,实现了添加、编辑和删除待办事项的功能。我们从环境设置开始,创建了主要的组件结构,实现了状态管理、展示待办事项列表和单个待办事项,然后进一步添加了样式和交互性改进。
功能和实现回顾
-
添加待办事项:通过输入框和"Enter"键,用户可以添加新的待办事项到列表中。
-
编辑待办事项:用户可以点击"编辑"按钮,进入编辑状态,修改待办事项的文本,并使用"Enter"键保存编辑。
-
删除待办事项:每个待办事项旁边有一个"删除"按钮,点击它可以从列表中删除该事项。
可能的改进方向
虽然我们已经实现了基本的功能,但还有许多改进的方向可以考虑,以进一步完善应用程序并增强用户体验。
-
持久化存储:将待办事项数据保存在浏览器本地存储或使用后端服务器进行数据存储,以便在刷新页面或关闭应用程序后保留数据。
-
任务状态:为每个待办事项添加一个状态,如“已完成”、“未完成”等。
-
日期和优先级:允许用户为每个待办事项设置截止日期和优先级,以更好地管理任务。
-
筛选和排序:为待办事项列表添加筛选和排序功能,使用户能够根据不同的标准查看和组织任务。
-
用户身份验证:实现用户注册和登录功能,为每个用户创建独立的待办事项列表。
-
提醒功能:添加提醒功能,允许用户设置提醒以确保不会错过重要任务。
-
样式和主题:进一步优化应用程序的样式,创建更吸引人的用户界面,并支持不同的主题选择。
-
动画效果:为添加、编辑和删除操作添加动画效果,增强用户的视觉体验。
-
移动适配:优化应用程序以适应不同的设备和屏幕大小,以便在移动设备上也能够良好地运行。
-
性能优化:考虑使用虚拟滚动等技术来处理大量待办事项时的性能问题。
以上只是一些可能的改进方向,根据您的项目目标和用户需求,您可以选择适当的改进方向来进一步发展和扩展您的待办事项列表应用程序。无论您选择哪个方向,持续地收集用户反馈,并根据反馈进行改进,将有助于您构建更加出色的应用程序。
完整的源代码示例
以下是完整的源代码示例,包括主应用程序组件、待办事项列表组件、待办事项单独显示组件、输入框组件以及样式文件。
App.js
import React, { useState } from 'react';
import TodoList from './TodoList';
import TodoInput from './TodoInput';
import './styles.css';
const App = () => {
const [todos, setTodos] = useState([]);
const [editTodo, setEditTodo] = useState(null);
const [editText, setEditText] = useState('');
const addTodo = text => {
const newTodo = { id: Date.now(), text };
setTodos([...todos, newTodo]);
};
const deleteTodo = id => {
const updatedTodos = todos.filter(todo => todo.id !== id);
setTodos(updatedTodos);
};
const editTodoItem = id => {
const todoToEdit = todos.find(todo => todo.id === id);
setEditTodo(todoToEdit);
setEditText(todoToEdit.text);
};
const saveEditTodo = id => {
const updatedTodos = todos.map(todo =>
todo.id === id ? { ...todo, text: editText } : todo
);
setTodos(updatedTodos);
setEditTodo(null);
};
return (
<div className="app">
<h1>Todo List</h1>
<TodoInput onAdd={addTodo} />
<TodoList todos={todos} onDelete={deleteTodo} onEdit={editTodoItem} />
{editTodo && (
<div className="edit-todo">
<input
type="text"
value={editText}
onChange={e => setEditText(e.target.value)}
onKeyDown={e => {
if (e.key === 'Enter' && editText.trim() !== '') {
saveEditTodo(editTodo.id);
}
}}
/>
</div>
)}
</div>
);
};
export default App;
TodoList.js
import React from 'react';
import TodoItem from './TodoItem';
const TodoList = ({ todos, onDelete, onEdit }) => {
return (
<div className="todo-list">
{todos.map(todo => (
<TodoItem
key={todo.id}
todo={todo}
onDelete={onDelete}
onEdit={onEdit}
/>
))}
</div>
);
};
export default TodoList;
TodoItem.js
import React, { useState } from 'react';
const TodoItem = ({ todo, onDelete, onEdit }) => {
const [editText, setEditText] = useState(todo.text);
const [isEditing, setIsEditing] = useState(false);
const saveEditTodo = () => {
onEdit(todo.id, editText);
setIsEditing(false);
};
return (
<div className="todo-item">
{isEditing ? (
<input
type="text"
value={editText}
onChange={e => setEditText(e.target.value)}
onKeyDown={e => {
if (e.key === 'Enter' && editText.trim() !== '') {
saveEditTodo();
}
}}
/>
) : (
<span>{todo.text}</span>
)}
<button onClick={() => setIsEditing(!isEditing)}>
{isEditing ? '保存' : '编辑'}
</button>
<button onClick={() => onDelete(todo.id)}>删除</button>
</div>
);
};
export default TodoItem;
TodoInput.js
import React, { useState } from 'react';
const TodoInput = ({ onAdd }) => {
const [text, setText] = useState('');
const handleKeyDown = event => {
if (event.key === 'Enter' && text.trim() !== '') {
onAdd(text);
setText('');
}
};
return (
<input
type="text"
placeholder="添加待办事项"
value={text}
onChange={e => setText(e.target.value)}
onKeyDown={handleKeyDown}
/>
);
};
export default TodoInput;
styles.css
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
}
.app {
text-align: center;
padding: 20px;
}
.todo-list {
display: flex;
flex-direction: column;
align-items: flex-start;
margin-top: 20px;
}
.todo-item {
display: flex;
align-items: center;
margin-bottom: 10px;
}
.todo-item span {
margin-right: 10px;
}
.edit-todo input {
width: 100%;
padding: 5px;
border: 1px solid #ccc;
border-radius: 4px;
}
参考资料和资源链接
以下是一些有关React和前端开发的参考资料和资源链接,可以帮助您进一步学习和扩展您的技能:
-
React 官方文档:React框架的官方文档,包含详细的指南、教程和API文档。
-
MDN Web 文档:MDN提供了丰富的前端开发文档和教程,涵盖HTML、CSS、JavaScript等方面。
-
React Router 官方文档:用于在React应用程序中实现导航和路由的React Router库的官方文档。
-
Bootstrap 官方文档:Bootstrap是一个流行的前端CSS库,用于构建响应式和美观的界面。
-
Tailwind CSS 官方文档:Tailwind CSS是另一个流行的CSS框架,提供了一组实用的类来快速构建界面。
-
React 开发者工具:浏览器扩展,用于在开发过程中检查和调试React应用程序。
-
Webpack 官方文档:Webpack是一个用于打包和构建前端资源的工具,可以优化您的应用程序的性能和加载时间。
-
Babel 官方文档:Babel是一个用于将新版JavaScript代码转换为