React实战小练手

284 阅读4分钟

React 待办事项列表应用详细实现与解析

前端实践选题:使用React 实现一个简单的待办事项列表:用户可以添加、编辑和删除待办事项

一、项目初始化与基础设置

1. 创建React项目

首先,我们需要创建一个新的React项目。如果已经安装了Node.js和npm(或yarn),可以使用Create React App这一官方脚手架工具来快速生成项目模板。

npx create-react-app todoList-app
cd todoList-app
npm start

运行上述命令后,我们得到了一个基础的React项目结构,并启动了一个开发服务器,可以在浏览器中访问http://localhost:3000查看默认的应用页面。

2. 项目目录结构

在开发过程中,合理的目录结构有助于代码的组织和维护。对于我们的待办事项列表应用,可以设计如下的目录结构:

todo-app/
├── node_modules/
├── public/
├── src/
│   ├── App.js
│   ├── TodoForm.js
│   ├── TodoItem.js
│   ├── TodoList.js
│   ├── index.js
├── package.json
├── README.md
└── ...
  • src/App.js:应用的主组件。
  • src/TodoForm.js:用于添加待办事项的表单组件。
  • src/TodoItem.js:表示单个待办事项的组件。
  • src/TodoList.js:展示待办事项列表的组件。

对于这个简单的待办事项列表应用来说,我们也只需要React和React DOM这两个核心库就足够了。

二、应用主组件的实现

1. App.js

App.js文件是应用的主入口点,它负责渲染整个应用的UI结构。在这个文件中,我们将引入TodoFormTodoList两个子组件,并通过状态管理来存储和更新待办事项列表。

import React, { useState } from "react";
import TodoForm from "./TodoForm";
import TodoList from "./TodoList";
import "./styles/App.css";

function App() {
  const [todos, setTodos] = useState([]);

  // 添加待办事项
  const addTodo = (todo) => {
    setTodos([...todos, todo]);
  };

  // 编辑待办事项
  const editTodo = (id, updatedTodo) => {
    setTodos(todos.map((todo) => (todo.id === id ? { ...todo, ...updatedTodo } : todo)));
  };

  // 删除待办事项
  const deleteTodo = (id) => {
    setTodos(todos.filter((todo) => todo.id !== id));
  };

  // 标记完成或未完成
  const toggleComplete = (id) => {
    setTodos(
      todos.map((todo) =>
        todo.id === id ? { ...todo, isCompleted: !todo.isCompleted } : todo
      )
    );
  };

  return (
    <div className="App">
      <h1>待办事项列表</h1>
      <TodoForm addTodo={addTodo} />
      <TodoList
        todos={todos}
        toggleComplete={toggleComplete}
        deleteTodo={deleteTodo}
        editTodo={editTodo}
      />
    </div>
  );
}

export default App;

App组件中,我们使用了useState钩子来管理待办事项列表的状态。addTodoeditTododeleteTodotoggleComplete这四个函数分别用于处理添加、编辑、删除和标记完成状态的操作。这些函数会更新todos状态,从而触发组件的重新渲染。

2. 样式文件(App.css)

为了美化我们的应用,可以添加一些基本的CSS样式。在src/styles/App.css文件中,我们可以定义一些样式规则来控制布局和外观。

.App {
  text-align: center;
  margin-top: 50px;
}

.todo-form {
  margin-bottom: 20px;
}

.todo-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 10px;
  padding: 10px;
  border: 1px solid #ccc;
  border-radius: 5px;
}

.todo-item input[type="checkbox"] {
  margin-right: 10px;
}

.todo-item span {
  flex: 1;
}

.todo-item button {
  margin-left: 10px;
}

.completed {
  background-color: #e0e0e0;
  text-decoration: line-through;
}

这些样式规则可以帮助我们创建一个整洁、易读的待办事项列表界面。

三、表单组件的实现

1. TodoForm.js

TodoForm组件是一个简单的表单,用于添加新的待办事项。它包含两个输入框,分别用于输入任务内容和截止日期,以及一个提交按钮。

import React, { useState } from "react";

function TodoForm({ addTodo }) {
  const [content, setContent] = useState("");
  const [deadline, setDeadline] = useState("");

  // 提交表单,创建新任务
  const handleSubmit = (e) => {
    e.preventDefault();
    if (content && deadline) {
      addTodo({
        id: Date.now(), // 使用当前时间作为唯一 ID
        content,
        deadline,
        isCompleted: false,
      });
      setContent(""); // 清空输入框
      setDeadline(""); // 清空日期输入框
    }
  };

  return (
    <form className="todo-form" onSubmit={handleSubmit}>
      <input
        type="text"
        value={content}
        onChange={(e) => setContent(e.target.value)}
        placeholder="任务内容"
      />
      <input
        type="date"
        value={deadline}
        onChange={(e) => setDeadline(e.target.value)}
        placeholder="截止日期"
      />
      <button type="submit">添加任务</button>
    </form>
  );
}

export default TodoForm;

TodoForm组件中,我们使用了useState钩子来管理任务内容和截止日期的状态。当用户填写表单并提交时,handleSubmit函数会被调用。这个函数会检查输入的内容是否为空,如果不为空,则调用addTodo函数来添加新的待办事项,并清空输入框。

四、待办事项列表组件的实现

1. TodoList.js

TodoList组件负责展示待办事项列表。它接收一个待办事项数组作为属性,并根据这些待办事项的状态(已完成或未完成)将它们分为两个列表进行展示。

import React from "react";
import TodoItem from "./TodoItem.js";

function TodoList({ todos, toggleComplete, deleteTodo, editTodo }) {
  // 将待办事项按截止日期排序
  const sortedTodos = todos
    .filter((todo) => !todo.isCompleted)
    .sort((a, b) => new Date(a.deadline) - new Date(b.deadline));

  const completedTodos = todos.filter((todo) => todo.isCompleted);

  return (
    <div>
      <h2>未完成的任务</h2>
      {sortedTodos.length > 0 ? (
        sortedTodos.map((todo) => (
          <TodoItem
            key={todo.id}
            todo={todo}
            toggleComplete={toggleComplete}
            deleteTodo={deleteTodo}
            editTodo={editTodo}
          />
        ))
      ) : (
        <p>没有待办事项</p>

实现效果

image.png