使用React和Material-UI构建TODO应用的前端UI

news2025/2/5 14:16:20

使用React和Material-UI构建TODO应用的前端UI

        • 引言
        • 环境准备
        • 代码解析
          • 1. 导入必要的模块
          • 2. 创建React组件
          • 3. 定义函数
            • 3.1 获取TODO列表
            • 3.2 创建TODO项
            • 3.3 更新TODO项
            • 3.4 删除TODO项
            • 3.5 处理编辑点击事件
            • 3.6 关闭编辑对话框
            • 3.7 保存编辑内容
          • 4. 使用Effect钩子
          • 5. 渲染组件
        • 功能实现
        • 优化建议
        • 总结

引言

在现代Web开发中,TODO列表应用是一个经典的示例,用于展示如何使用前端技术构建一个简单的任务管理工具。本文将详细介绍如何使用React框架和Material-UI库来构建一个TODO列表应用,并解释代码的各个部分,帮助读者理解其工作原理。

后端API请参考,使用Express.js和SQLite3构建简单TODO应用的后端API

环境准备

在开始之前,请确保你已经安装了以下工具和库:

  1. Node.js:确保你已经安装了Node.js,可以从Node.js官网下载并安装。
  2. npm:Node.js的包管理工具,随Node.js一起安装。
  3. React:一个用于构建用户界面的JavaScript库,可以通过npm安装。
  4. Material-UI:一个基于Material Design的React组件库,同样可以通过npm安装。
  5. axios:一个基于Promise的HTTP客户端,用于处理API请求。

安装所需的依赖:

npm install react @mui/material @emotion/react @emotion/styled axios
代码解析

让我们逐步分析代码,理解每个部分的功能。

1. 导入必要的模块
import { useState, useEffect } from 'react';
import axios from 'axios';
import {
    TextField,
    Button,
    Checkbox,
    List,
    ListItem,
    ListItemText,
    IconButton,
    Dialog,
    DialogTitle,
    DialogContent,
    DialogActions,
    FormControlLabel
} from '@mui/material';
import { Delete, Edit } from '@mui/icons-material';
import { Todo } from '../types/todo';
  • React:导入useStateuseEffect钩子,用于状态管理和副作用处理。
  • axios:用于发送HTTP请求。
  • Material-UI:导入各种组件,如文本框、按钮、列表、对话框等。
  • Icons:导入删除和编辑图标。
  • Todo类型:定义TODO项的类型,确保数据的类型安全。
2. 创建React组件
export default function TodoList() {
    const [todos, setTodos] = useState<Todo[]>([]);
    const [searchTerm, setSearchTerm] = useState('');
    const [newTodo, setNewTodo] = useState({ title: '', description: '' });
    const [editingTodo, setEditingTodo] = useState<Todo | null>(null);
    const [editForm, setEditForm] = useState({ title: '', description: '', completed: false });
  • todos:存储TODO列表的状态。
  • searchTerm:存储搜索词的状态。
  • newTodo:存储新TODO项的状态。
  • editingTodo:存储正在编辑的TODO项的状态。
  • editForm:存储编辑表单的状态。
3. 定义函数
3.1 获取TODO列表
const fetchTodos = async () => {
    try {
        const response = await axios.get(`http://localhost:3002/api/todos?q=${searchTerm}`);
        setTodos(response.data);
    } catch (error) {
        console.error('Error fetching todos:', error);
    }
};
  • 功能:从后端获取TODO列表,支持搜索功能。
  • 实现:使用axios.get发送GET请求,根据searchTerm进行模糊搜索。
3.2 创建TODO项
const createTodo = async () => {
    if (!newTodo.title.trim()) return;
    try {
        await axios.post('http://localhost:3002/api/todos', newTodo);
        setNewTodo({ title: '', description: '' });
        fetchTodos();
    } catch (error) {
        console.error('Error creating todo:', error);
    }
};
  • 功能:创建一个新的TODO项。
  • 实现:检查标题是否为空,使用axios.post发送POST请求,创建成功后清空表单并刷新列表。
3.3 更新TODO项
const updateTodo = async (todo: Todo, isToggleComplete = false) => {
    try {
        const updatedTodo = isToggleComplete
            ? { ...todo, completed: !todo.completed }
            : { ...todo, title: editForm.title, description: editForm.description, completed: editForm.completed };

        await axios.put(`http://localhost:3002/api/todos/${todo.id}`, updatedTodo);
        setEditingTodo(null);
        fetchTodos();
    } catch (error) {
        console.error('Error updating todo:', error);
    }
};
  • 功能:更新TODO项,支持标记完成和编辑内容。
  • 实现:根据isToggleComplete决定是更新完成状态还是编辑内容,使用axios.put发送PUT请求。
3.4 删除TODO项
const deleteTodo = async (id: number) => {
    try {
        await axios.delete(`http://localhost:3002/api/todos/${id}`);
        fetchTodos();
    } catch (error) {
        console.error('Error deleting todo:', error);
    }
};
  • 功能:删除指定的TODO项。
  • 实现:使用axios.delete发送DELETE请求,删除成功后刷新列表。
3.5 处理编辑点击事件
const handleEditClick = (todo: Todo) => {
    setEditingTodo(todo);
    setEditForm({
        title: todo.title,
        description: todo.description || '',
        completed: todo.completed
    });
};
  • 功能:打开编辑对话框,填充TODO项的详细信息。
  • 实现:设置editingTodoeditForm状态,显示编辑表单。
3.6 关闭编辑对话框
const handleClose = () => {
    setEditingTodo(null);
    setEditForm({ title: '', description: '', completed: false });
};
  • 功能:关闭编辑对话框,重置表单。
  • 实现:清除editingTodoeditForm状态。
3.7 保存编辑内容
const handleSave = () => {
    if (editingTodo && editForm.title.trim()) {
        updateTodo(editingTodo);
    }
};
  • 功能:保存编辑的内容。
  • 实现:检查标题是否为空,调用updateTodo更新TODO项。
4. 使用Effect钩子
useEffect(() => {
    const debounceSearch = setTimeout(() => {
        fetchTodos();
    }, 300);

    return () => clearTimeout(debounceSearch);
}, [searchTerm]);
  • 功能:实现搜索的防抖动效果,防止频繁请求。
  • 实现:使用setTimeout延迟300毫秒后执行fetchTodos,并在组件销毁时清除定时器。
5. 渲染组件
return (
    <div style={{ maxWidth: 600, margin: '0 auto', padding: '20px' }}>
        <TextField
            fullWidth
            label="Search Todos"
            variant="outlined"
            value={searchTerm}
            onChange={(e) => setSearchTerm(e.target.value)}
            margin="normal"
        />

        <List>
            {todos.map((todo) => (
                <ListItem
                    key={todo.id}
                    secondaryAction={(
                        <>
                            <IconButton onClick={() => handleEditClick(todo)}>
                                <Edit />
                            </IconButton>
                            <IconButton onClick={() => deleteTodo(todo.id)}>
                                <Delete />
                            </IconButton>
                        </>
                    )}
                    style={{
                        display: todo.completed ? 'none' : 'flex',
                        opacity: todo.completed ? 0.7 : 1
                    }}
                >
                    <Checkbox
                        checked={Boolean(todo.completed)}
                        onChange={() => updateTodo(todo, true)}
                    />
                    <ListItemText
                        primary={todo.title}
                        secondary={todo.description}
                        style={{
                            textDecoration: todo.completed ? 'line-through' : 'none',
                        }}
                    />
                </ListItem>
            ))}
        </List>

        <div style={{ display: 'flex', gap: 10, marginBottom: 20 }}>
            <TextField
                fullWidth
                label="New Todo Title"
                value={newTodo.title}
                onChange={(e) => setNewTodo({ ...newTodo, title: e.target.value })}
            />
            <TextField
                fullWidth
                label="Description"
                value={newTodo.description}
                onChange={(e) => setNewTodo({ ...newTodo, description: e.target.value })}
            />
            <Button
                variant="contained"
                color="primary"
                onClick={createTodo}
            >
                Add
            </Button>
        </div>

        <Dialog open={Boolean(editingTodo)} onClose={handleClose}>
            <DialogTitle>Edit Todo</DialogTitle>
            <DialogContent>
                <TextField
                    autoFocus
                    margin="dense"
                    label="Title"
                    fullWidth
                    value={editForm.title}
                    onChange={(e) => setEditForm({ ...editForm, title: e.target.value })}
                />
                <TextField
                    margin="dense"
                    label="Description"
                    fullWidth
                    multiline
                    rows={3}
                    value={editForm.description}
                    onChange={(e) => setEditForm({ ...editForm, description: e.target.value })}
                />
                <FormControlLabel
                    control={(
                        <Checkbox
                            checked={editForm.completed}
                            onChange={(e) => setEditForm({ ...editForm, completed: e.target.checked })}
                        />
                    )}
                    label="Completed"
                />
            </DialogContent>
            <DialogActions>
                <Button onClick={handleClose} color="primary">
                    Cancel
                </Button>
                <Button
                    onClick={handleSave}
                    color="primary"
                    disabled={!editForm.title.trim()}
                >
                    Save
                </Button>
            </DialogActions>
        </Dialog>
    </div>
);
  • 搜索框:允许用户输入搜索词,实时搜索TODO列表。
  • TODO列表:显示所有TODO项,每个项包含标题、描述、编辑和删除按钮,以及完成状态Checkbox。
  • 添加TODO表单:允许用户输入新TODO的标题和描述,点击“Add”按钮创建。
  • 编辑对话框:当用户点击编辑按钮时,显示编辑表单,允许修改TODO的标题、描述和完成状态。
功能实现
  1. 添加TODO项:用户输入标题和描述后,点击“Add”按钮,发送POST请求到后端,创建新的TODO项。
  2. 编辑TODO项:用户点击编辑按钮,打开编辑对话框,修改TODO项的详细信息后,点击“Save”按钮,发送PUT请求到后端,更新TODO项。
  3. 删除TODO项:用户点击删除按钮,发送DELETE请求到后端,删除指定的TODO项。
  4. 搜索TODO项:用户输入搜索词,组件会自动搜索标题或描述中包含该词的TODO项,支持防抖动功能,减少请求次数。
  5. 标记完成:用户点击Checkbox,TODO项会被标记为完成,样式会变为灰色并添加删除线。
优化建议

尽管这段代码已经可以正常工作,但为了提升应用的性能和用户体验,可以考虑以下优化:

  1. 添加加载状态:在数据加载过程中,显示加载动画,提升用户体验。
  2. 添加错误提示:在请求失败时,显示错误提示信息,帮助用户了解问题所在。
  3. 添加成功提示:在创建、更新或删除TODO项成功后,显示成功提示信息。
  4. 优化样式:根据Material Design规范,优化组件的样式和布局,提升视觉效果。
  5. 添加响应式设计:确保应用在不同设备上都能良好显示,提升应用的适应性。
  6. 添加数据验证:在前端和后端都添加数据验证,确保输入的数据合法有效。
总结

通过本文,我们详细解析了一个使用React和Material-UI构建的TODO列表应用。从状态管理、HTTP请求到组件渲染,每个部分都进行了详细的解释。希望这篇文章能够帮助读者理解如何使用这些技术构建一个简单的TODO应用,并为进一步的学习和开发打下基础。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2292344.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ChatGPT提问技巧:行业热门应用提示词案例--咨询法律知识

ChatGPT除了可以协助办公&#xff0c;写作文案和生成短视频脚本外&#xff0c;和还可以做为一个法律工具&#xff0c;当用户面临一些法律知识盲点时&#xff0c;可以向ChatGPT咨询获得解答。赋予ChatGPT专家的身份&#xff0c;用户能够得到较为满意的解答。 1.咨询法律知识 举…

[吾爱出品]CursorWorkshop V6.33 专业鼠标光标制作工具-简体中文汉化绿色版

CursorWorkshop V6.33 专业鼠标光标制作工具 链接&#xff1a;https://pan.xunlei.com/s/VOIFeq5DFB9FS56Al_mT2EfdA1?pwd7ij4# 产品概述 Axialis CursorWorkshop 是一个专业光标创作工具它在 Windows 下运行&#xff0c;让您轻松创建高质量的静态和动态光标适用于 Windows …

【C语言】自定义类型讲解

文章目录 一、前言二、结构体2.1 概念2.2 定义2.2.1 通常情况下的定义2.2.2 匿名结构体 2.3 结构体的自引用和嵌套2.4 结构体变量的定义与初始化2.5 结构体的内存对齐2.6 结构体传参2.7 结构体实现位段 三、枚举3.1 概念3.2 定义3.3 枚举的优点3.3.1 提高代码的可读性3.3.2 防止…

LabVIEW涡轮诊断系统

一、项目背景与行业痛点 涡轮机械是发电厂、航空发动机、石油化工等领域的核心动力设备&#xff0c;其运行状态直接关系到生产安全与经济效益。据统计&#xff0c;涡轮故障导致的非计划停机可造成每小时数十万元的经济损失&#xff0c;且突发故障可能引发严重安全事故。传统人…

Kubernetes 中 BGP 与二层网络的较量:究竟孰轻孰重?

如果你曾搭建过Kubernetes集群&#xff0c;就会知道网络配置是一个很容易让人深陷其中的领域。在负载均衡器、服务通告和IP管理之间&#xff0c;你要同时应对许多变动的因素。对于许多配置而言&#xff0c;使用二层&#xff08;L2&#xff09;网络就完全能满足需求。但边界网关…

大模型综述一镜到底(全文八万字) ——《Large Language Models: A Survey》

论文链接&#xff1a;https://arxiv.org/abs/2402.06196 摘要&#xff1a;自2022年11月ChatGPT发布以来&#xff0c;大语言模型&#xff08;LLMs&#xff09;因其在广泛的自然语言任务上的强大性能而备受关注。正如缩放定律所预测的那样&#xff0c;大语言模型通过在大量文本数…

物理群晖SA6400核显直通win10虚拟机(VMM)

写在前面&#xff1a;请先确保你的核显驱动支持开启SR-IOV 确保你的BIOS开启了以下选项&#xff1a; VT-D VMX IOMMU Above 4G ResizeBAR 自行通过以下命令确认支持情况&#xff1a; dmesg | grep -i iommudmesg | grep DMAR分配1个虚拟vGPU&#xff1a;echo 1 | sudo tee /sy…

【python】tkinter实现音乐播放器(源码+音频文件)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;专__注&#x1f448;&#xff1a;专注主流机器人、人工智能等相关领域的开发、测试技术。 【python】tkinter实现音乐播放器&#xff08;源码…

MyBatis-Plus速成指南:常用注解

Table Name: 概述&#xff1a; MyBatis-Plus 在确定操作的表时&#xff0c;由 BaseMapper的泛型决定&#xff0c;即实体类决定&#xff0c;且默认操作的表名和实体类的类名一致 问题&#xff1a; 如果实体类类型的类名和要操作表的表名不一致会出现什么问题&#xff1f;(把 us…

Linux 压缩打包

Linux压缩打包 文章目录 Linux压缩打包压缩的意义和原理压缩的意义压缩的原理压缩与解压缩的好处 压缩打包命令.zipzip 命令用法unzip 的用法 .gzgzip 的用法gunzip 的用法 .bz2bzip2 的用法bunzip2 的用法 .xzxz 命令用法 tar 04-Linux压缩打包课后习题 压缩的意义和原理 压缩…

RabbitMQ深度探索:前置知识

消息中间件&#xff1a; 消息中间件基于队列模式实现异步 / 同步传输数据作用&#xff1a;可以实现支撑高并发、异步解耦、流量削峰、降低耦合 传统的 HTTP 请求存在的缺点&#xff1a; HTTP 请求基于响应的模型&#xff0c;在高并发的情况下&#xff0c;客户端发送大量的请求…

智慧校园平台:构建现代化教育体系的技术支撑

在当今信息技术飞速发展的时代&#xff0c;智慧校园平台成为了现代教育领域中的重要组成部分。智慧校园平台不仅能够提升学校的管理水平&#xff0c;还能提供更为个性化和高效的教学服务&#xff0c;从而促进学生的全面发展。 数据分析是智慧校园平台的重要组成部分。通过对学生…

20250204将Ubuntu22.04的默认Dash的shell脚本更换为bash

20250204将Ubuntu22.04的默认Dash的shell脚本更换为bash 2025/2/4 23:45 百度&#xff1a;dash bash https://blog.csdn.net/2201_75772333/article/details/136955776 【Linux基础】dash和bash简介 Dash&#xff08;Debian Almquist Shell&#xff09;和 Bash&#xff08;Bou…

Golang 并发机制-3:通道(channels)机制详解

并发编程是一种创建性能优化且响应迅速的软件的强大方法。Golang&#xff08;也称为 Go&#xff09;通过通道&#xff08;channels&#xff09;这一特性&#xff0c;能够可靠且优雅地实现并发通信。本文将揭示通道的概念&#xff0c;解释其在并发编程中的作用&#xff0c;并提供…

可视化大屏在石油方面的应用。

可视化大屏通过整合石油工业全链条数据&#xff0c;构建数字孪生驱动的运营监控体系&#xff0c;显著提升油气勘探、开采、储运及炼化的管理效能。其技术架构依托工业物联网&#xff08;IIoT&#xff09;实时采集钻井参数、管道压力、储罐液位等数据&#xff0c;通过OPC UA协议…

【学术投稿-2025年计算机视觉研究进展与应用国际学术会议 (ACVRA 2025)】从计算机基础到HTML开发:Web开发的第一步

会议官网&#xff1a;www.acvra.org 简介 2025年计算机视觉研究进展与应用&#xff08;ACVRA 2025&#xff09;将于2025年2月28-3月2日在中国广州召开&#xff0c;将汇聚世界各地的顶尖学者、研究人员和行业专家&#xff0c;聚焦计算机视觉领域的最新研究动态与应用成就。本次…

Axure PR 9 旋转效果 设计交互

大家好&#xff0c;我是大明同学。 这期内容&#xff0c;我们将学习Axure中的旋转效果设计与交互技巧。 旋转 创建旋转效果所需的元件 1.打开一个新的 RP 文件并在画布上打开 Page 1。 2.在元件库中拖出一个按钮元件。 创建交互 创建按钮交互状态 1.选中按钮元件&#xf…

Docker 部署教程jenkins

Docker 部署 jenkins 教程 Jenkins 官方网站 Jenkins 是一个开源的自动化服务器&#xff0c;主要用于持续集成&#xff08;CI&#xff09;和持续交付&#xff08;CD&#xff09;过程。它帮助开发人员自动化构建、测试和部署应用程序&#xff0c;显著提高软件开发的效率和质量…

计算图 Compute Graph 和自动求导 Autograd | PyTorch 深度学习实战

前一篇文章&#xff0c;Tensor 基本操作5 device 管理&#xff0c;使用 GPU 设备 | PyTorch 深度学习实战 本系列文章 GitHub Repo: https://github.com/hailiang-wang/pytorch-get-started PyTorch 计算图和 Autograd 微积分之于机器学习Computational Graphs 计算图Autograd…

接入DeepSeek大模型

接入DeepSeek 下载并安装Ollamachatbox 软件配置大模型 下载并安装Ollama 下载并安装Ollama&#xff0c; 使用参数ollama -v查看是否安装成功。 输入命令ollama list&#xff0c; 可以看到已经存在4个目录了。 输入命令ollama pull deepseek-r1:1.5b&#xff0c; 下载deepse…