本文旨在使用React 实现一个简单的待办事项列表,用户可以添加、编辑和删除待办事项。
预览
开始之前
在开始之前,首先确保已经安装了Node.js和npm(Node.js包管理器)。在命令行中运行以下命令来检查它们是否已安装:
node -v
npm -v
如果没有安装,可以从官方网站下载并安装它们。
初始化项目
首先,我们需要创建一个新的React应用。在命令行中执行以下步骤:
- 创建一个新文件夹,并进入该文件夹:
mkdir React-Todo-list-main
cd React-Todo-list-main
- 使用
create-react-app命令初始化一个新的React项目:
npx create-react-app .
这会在当前文件夹中创建一个新的React项目。
编写代码
App
- App里引入一个TodoWrapper组件,TodoWrapper组件下面应该有三个组件,一个负责输入添加一条新的
TodoForm,一个负责展示list数据的Todo,每条数据后面要有删除和编辑的功能按钮,还有一个编辑数据的EditTodoForm。
src/App.js 代码
import "./App.css";
import { TodoWrapper } from "./Components/TodoWrapper";
function App() {
return (
<div className="App">
<TodoWrapper />
</div>
);
}
export default App;
TodoForm
2.新建一个名为 TodoForm 的 React 组件,用于添加新的待办任务。
定义一个名为 TodoForm 的函数式组件。它接收一个属性 addTodo,该属性是一个函数,用于添加新的待办任务。
- 当表单提交时,该函数
handleSubmit被调用。 - 使用
e.preventDefault()阻止默认的表单提交行为(避免页面刷新)。 - 如果
value不为空,调用传入的addTodo函数,将输入的任务内容作为参数传递进去。 - 提交后,将输入框的值清空。
返回 JSX(用户界面元素),包括一个表单,用户可以在其中输入新的待办任务。
- 表单的
onSubmit处理程序被设置为前面定义的handleSubmit函数。 - 使用
<input>元素,允许用户输入待办任务的内容。输入框的value受value状态控制,onChange处理程序在用户输入时更新value状态。 - 在输入框中显示 "输入我的To Do!" 占位符。
- 提供了一个
<button>元素,用于提交新的待办任务。
import React, {useState} from 'react'
export const TodoForm = ({addTodo}) => {
const [value, setValue] = useState('');
const handleSubmit = (e) => {
// 阻止默认的提交行为
e.preventDefault();
if (value) {
// 添加待办任务
addTodo(value);
// 提交后清空表单
setValue('');
}
};
return (
<form onSubmit={handleSubmit} className="TodoForm">
<input type="text" value={value} onChange={(e) => setValue(e.target.value)} className="todo-input" placeholder='Input my ToDo !' />
<button type="submit" className='todo-btn'>Add Task</button>
</form>
)
}
Todo
3.新建一个名为 Todo 的 React 组件,用于显示单个待办任务。
引入 React 组件和一些图标,其中包括 FontAwesomeIcon 组件用于显示 Font Awesome 图标。faPenToSquare 和 faTrash 是两个具体的图标,分别用于表示编辑和删除操作。
定义一个名为 Todo 的函数式组件。它接收四个属性:task(表示任务的对象)、deleteTodo(用于删除任务的函数)、editTodo(用于编辑任务的函数)和 toggleComplete(用于切换任务完成状态的函数)。
返回 JSX(用户界面元素),用于显示单个待办任务的内容。
<p>元素显示任务的文本内容。如果任务的completed属性为true,则会给<p>元素添加completed类名,以应用样式(例如:划掉文本)。点击<p>元素时,会调用toggleComplete函数来切换任务的完成状态。<div>元素包含两个图标,分别用于编辑和删除操作。<FontAwesomeIcon>组件用于渲染 Font Awesome 图标。点击图标时,会调用相应的函数(editTodo或deleteTodo),并传递任务的 ID 作为参数。
import React from 'react'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faPenToSquare } from '@fortawesome/free-solid-svg-icons'
import { faTrash } from '@fortawesome/free-solid-svg-icons'
export const Todo = ({task, deleteTodo, editTodo, toggleComplete}) => {
return (
<div className="Todo">
<p className={`${task.completed ? 'completed' : ""}`} onClick={() => toggleComplete(task.id)}>{task.task}</p>
<div>
<FontAwesomeIcon icon={faPenToSquare} onClick={() => editTodo(task.id)} />
<FontAwesomeIcon icon={faTrash} onClick={() => deleteTodo(task.id)} />
</div>
</div>
)
}
EditTodoForm
4.新建一个名为 EditTodoForm 的 React 组件,用于编辑现有的待办任务。
-
定义一个名为
EditTodoForm的函数式组件。它接收两个属性:editTodo(用于编辑待办任务的函数)和task(表示要编辑的任务的对象)。 -
使用
useStateHook 初始化一个状态片段,名为value。它被初始化为task.task的值,即当前任务的文本内容。setValue函数用于更新状态。 -
当表单提交时,函数
handleSubmit被调用。它使用e.preventDefault()阻止了默认的表单提交行为(这会导致页面刷新)。然后,它调用了提供的editTodo函数,传递了更新后的任务文本和任务的 ID。
返回 JSX(用户界面元素),构成用于编辑待办任务的表单。
- 表单的
onSubmit处理程序被设置为前面定义的handleSubmit函数。 - 使用
<input>元素,允许用户输入更新后的任务文本。输入框的value受value状态控制,onChange处理程序在用户输入时更新value状态。 - 在输入框中显示 "更新任务" 占位符。
- 提供了一个
<button>元素,用于提交更新后的任务。
import React, {useState} from 'react'
export const EditTodoForm = ({editTodo, task}) => {
const [value, setValue] = useState(task.task);
const handleSubmit = (e) => {
// prevent default action
e.preventDefault();
// edit todo
editTodo(value, task.id);
};
return (
<form onSubmit={handleSubmit} className="TodoForm">
<input type="text" value={value} onChange={(e) => setValue(e.target.value)} className="todo-input" placeholder='Update task' />
<button type="submit" className='todo-btn'>Add Task</button>
</form>
)
}
TodoWrapper
5.新建一个名为 TodoWrapper 的 React 组件,是一个待办事项列表的容器。
引入 React 组件、自定义组件、用于生成唯一 ID 的 uuidv4 函数。
使用 useState Hook 初始化一个状态 todos,初始值为空数组。setTodos 函数用于更新这个状态,存储待办任务列表。
addTodo函数用于添加新的待办任务。它通过展开现有任务列表并添加新的任务对象来更新todos状态。每个新任务都有一个唯一的 ID(使用uuidv4()函数生成)、任务内容task、完成状态completed(初始为false)、编辑状态isEditing(初始为false)。deleteTodo函数删除指定 ID 的待办任务。toggleComplete函数切换指定 ID 的待办任务的完成状态。editTodo函数切换指定 ID 的待办任务的编辑状态。editTask函数用于编辑待办任务的文本内容。它更新指定 ID 的任务的task属性,并切换编辑状态isEditing。
返回 JSX(用户界面元素),用于显示待办清单的内容。
- 包含一个标题
<h1>。 - 包含一个
TodoForm组件,用于添加新的待办任务。 - 使用
.map方法遍历todos列表,并根据isEditing属性来渲染相应的组件。如果isEditing为true,则渲染EditTodoForm组件,否则渲染Todo组件,同时传递相应的属性。这样可以实现编辑和显示待办任务的切换。
import React, { useState } from "react";
import { Todo } from "./Todo";
import { TodoForm } from "./TodoForm";
import { v4 as uuidv4 } from "uuid";
import { EditTodoForm } from "./EditTodoForm";
export const TodoWrapper = () => {
const [todos, setTodos] = useState([]);
const addTodo = (todo) => {
setTodos([
...todos,
{ id: uuidv4(), task: todo, completed: false, isEditing: false },
]);
}
const deleteTodo = (id) => setTodos(todos.filter((todo) => todo.id !== id));
const toggleComplete = (id) => {
setTodos(
todos.map((todo) =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
)
);
}
const editTodo = (id) => {
setTodos(
todos.map((todo) =>
todo.id === id ? { ...todo, isEditing: !todo.isEditing } : todo
)
);
}
const editTask = (task, id) => {
setTodos(
todos.map((todo) =>
todo.id === id ? { ...todo, task, isEditing: !todo.isEditing } : todo
)
);
};
return (
<div className="TodoWrapper">
<h1>MY TO DO LIST !</h1>
<TodoForm addTodo={addTodo} />
{/* display todos */}
{todos.map((todo) =>
todo.isEditing ? (
<EditTodoForm editTodo={editTask} task={todo} />
) : (
<Todo
key={todo.id}
task={todo}
deleteTodo={deleteTodo}
editTodo={editTodo}
toggleComplete={toggleComplete}
/>
)
)}
</div>
);
};
CSS美化
6.为了美化应用,我们将添加一些基本的样式。在src文件夹中创建一个名为App.css的文件,并添加以下样式代码:
@import url('https://fonts.googleapis.com/css2?family=Poppins&display=swap');
* {
font-family: 'Poppins', sans-serif;
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: #38669d;
display: flex;
justify-content: center;
align-items: center;
}
.App {
text-align: center;
}
h1 {
color: #fff;
margin-bottom: 0.5rem;
font-size: 1.75rem;
}
.TodoWrapper {
background: #2ca7b8;
margin-top: 5rem;
padding: 2rem;
border-radius: 5px;
}
.TodoForm {
width: 100%;
}
.todo-input {
outline: none;
background: none;
border: 1px solid #86be37;
padding: 0.5rem 1rem;
margin-top: 1rem;
margin-bottom: 2rem;
width: 300px;
color: #fff;
}
.todo-input::placeholder {
color: #ffffff4d;
}
.todo-btn {
background: #d18072;
color: #fff;
border: none;
padding: 0.55rem;
cursor: pointer;
}
.Todo {
display: flex;
justify-content: space-between;
align-items: center;
background: #6746ca;
color: #fff;
padding: 0.75rem 1rem;
border-radius: 5px;
margin-bottom: 1rem;
cursor: pointer;
}
.fa-trash {
margin-left: 0.75rem;
}
.completed {
color: #1ab76e;
text-decoration: line-through;
}
实际效果
总结
使用React制作一个ToDoList是一个很好的入门级练习,可以学习如何使用React构建一个功能完整的应用。通过不断的学习和实践,可以进一步发展自己的React技能,并创建出更加复杂和强大的应用。