惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Hacker News: Ask HN
Hacker News: Ask HN
C
Cisco Blogs
The Hacker News
The Hacker News
T
Tor Project blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
The GitHub Blog
The GitHub Blog
A
Arctic Wolf
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
The Register - Security
The Register - Security
云风的 BLOG
云风的 BLOG
Simon Willison's Weblog
Simon Willison's Weblog
P
Palo Alto Networks Blog
Vercel News
Vercel News
C
CERT Recently Published Vulnerability Notes
I
InfoQ
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
M
MIT News - Artificial intelligence
I
Intezer
aimingoo的专栏
aimingoo的专栏
U
Unit 42
C
Cyber Attacks, Cyber Crime and Cyber Security
L
LINUX DO - 热门话题
Microsoft Security Blog
Microsoft Security Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
Cyberwarzone
Cyberwarzone
P
Proofpoint News Feed
P
Proofpoint News Feed
B
Blog
T
Threat Research - Cisco Blogs
博客园 - 叶小钗
Recorded Future
Recorded Future
Last Week in AI
Last Week in AI
N
News and Events Feed by Topic
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Know Your Adversary
Know Your Adversary
Engineering at Meta
Engineering at Meta
G
Google Developers Blog
PCI Perspectives
PCI Perspectives
Google DeepMind News
Google DeepMind News
WordPress大学
WordPress大学
Application and Cybersecurity Blog
Application and Cybersecurity Blog
MyScale Blog
MyScale Blog
Security Archives - TechRepublic
Security Archives - TechRepublic
Schneier on Security
Schneier on Security
N
News | PayPal Newsroom
C
Cybersecurity and Infrastructure Security Agency CISA
H
Help Net Security
博客园 - 聂微东
H
Hackread – Cybersecurity News, Data Breaches, AI and More
G
GRAHAM CLULEY

碎言

不懂就别瞎掰掰:【程序员的常识】写的什么玩意? PrimaryOralMathPack 小学生口算题生成器 AI 辅助编程下的程序设计与代码编写 使用 Next.js 和 Tailwind CSS 构建可编辑和删除的 ToDo 待办事项应用 探索编程新境界:MarsCode 助你一臂之力 使用 Next.js 和 Tailwind CSS 搭建静态图片展示站点并部署到 Vercel AI 辅助编程:免费工具的优缺点及官网一览 GitHub push更新总是失败,写个python脚本解决 把博客从GitHub迁移到到了vercel ComfyUI 和 Flux.1 安装与使用教程 Flux.1 入门必知:硬件、环境、模型 Git项目的子文件夹中的内容无法同步到远程仓库的解决方法 blender流体Fluid使用中没有流体、流体穿模等一些问题的解决方法 博客聚合网站:积薪,竟然关闭了! blender日常使用中的一些技巧 虽然只有我自己在用,但还是更新了碎言博客的源代码, 与其在迷茫中困惑,不如在努力中前进 差点忘了我还有一个博客... 秧歌、博客和AI 终于熬到了新手上路 好久没有更新博客了。。。 老妈大腿骨骨折,最近一直在医院护理 Hello, September! Ubuntu开机自动启动Docker容器运行WordPress Docker 简单快速安装部署WordPress Docker下安装MySQL 加碘盐能防核辐射的话,还怕什么核战争? shields.io 一个简洁、一致、清晰的徽章 Ubuntu下使用root登录ssh的设置 GitHub Actions 构建、部署 Next.js项目 我又用回了"IE"--edge ubuntu-22-live-server 设置固定IP Next项目部署GitHub pages的一些坑 整理了一个下午的收藏夹...... 短暂而忙碌的暑假即将谢幕 GitHub Actions 是干什么用的? 放弃Next.js重构博客:经验、教训与未来技术探索 关于Google LCP 问题:超过了2.5秒 验证已通过 仅用了几个小时就使用next.js重构博客的所有功能 关于使用Next.js重构博客构思的记录 使用Tailwind css和JavaScript实现一个简单的返回顶部功能 罗技K380 F1-F12 功能键锁定 PHILIPS猛禽SPK8404机械键盘手感真是超赞! 局域网的DNS设置192.168.0.1与8.8.8.8,114.114.114.114有什么区别? 史诗结合的浪漫:《长安三万里》 聊 聊 友 情 链 接 1767个中文博客的数据洞察:中文博主都喜欢干啥? python requests 设置读取超时时间 八月回顾:博客之路,一路前行 Docker基础学习笔记和常用命令汇总 vim常用命令整理 Ubuntu 22 安装Docker过程记录 使用python结合feedparser模块编写自己的私人RSS订阅程序 博客大数据分析:38880条博文揭示博主最爱写什么? Windows下国产杀毒软件还有选择吗?火绒安全可以一试。 export exports module.exports 这三个命令的区别是什么如何使用? 时代的变迁:从56K拨号上网到1G光纤的回忆 理工计算机专业准大学生如何选配笔记本? 使用JavaScript编写自己的私人RSS订阅程序 如何使用CSS为博客标题设置彩虹颜色? 最终还是决定使用传统的网线来解决千兆速率问题。 1300M USB双频2.4+5G无线网卡的一些常识和使用技巧 Python Gui新框架:NiceGui之初体验 pycharm 正在关闭项目(closing project)无法关闭退出程序的解决方法! 速度与优雅:博客性能优化之旅 久了,博客主题就会一直做减法 七月的焦虑 在react中使用复制插件clipboard.js react中如把HTML代码转成字符串进行渲染? react useEffect()中使用lodash库中的防抖debounce react useEffect() 为什么在开发模式的时候会执行两次? 七年之痒!别了我曾深爱的MacBookPro 前端React+Material UI开发环境的快速搭建 一键更新Github部署的静态博客 编程新手学习过程中如何更好的提问? Typed.js 一款有意思的网页打字机效果库 解决错误 ERROR [WinError 10049] 在其上下文中,该请求的地址无效。 Stable Diffusion 相关教程与模型的记录 Stable Diffusion ControlNet openpose 报错无法使用 在react或vue中使用localStorage存储数据 碎言静态博客 聊聊Python中的装饰器 npm更换源与nrm安装与配置 pip临时修改下载源 Vue快速学习笔记(9)Vuetify配置及简单使用 Vue快速学习笔记(8)webpack4.X配置Vue开发打包环境 Vue快速学习笔记(5)使用路由vue-router(1) Vue快速学习笔记(4)Vue组件中的数据传递 Vue快速学习笔记(3)Vue的组件 Vue快速学习笔记(2)Vue中的监听与计算属性 Vue快速学习笔记(1)Vue实例基础 基于Django构建的小学生英文单词背写检测考试系统。 如何在Python程序中使用配置文件.ini(ConfigParser) 写在我的博客PV10万时:聊聊编程与画画 python3函数学习笔记简单总结 PythonINI配置文件读写的简单方法 Python open()函数文件打开、读、写操作总结 Python os.path模块中一些常用方法的整理总结 Python 采集数据三步曲之[Requests + re.py模块进行数据采集] Python 采集数据三步曲之[Requests开源协议的HTTP 库]
使用React+Vite+TailwindCSS+daisyUI打造一个简单的ToDos
J.sky · 2023-06-29 · via 碎言

闲来无事,琢磨着体验一下react吧,花了一天的时间看了看react的官方文档,然后能照着以前用vue写的ToDo使用react重构了一遍,这里简单记录并总结一下学习过程。

效果如下:

矩阵头像

环境搭建

关于React+Vite+TailwindCSS+daisyUI的环境搭建之前写过一篇博客,这里就不在重复了,传送门:前端React+TailwindCSS+daisyUI开发环境的快速搭建,环境的搭建很简单的,大家看看就能明白了。

编写ToDo

ToDo的核心就是把一个存有待办事项的数组通过react渲染出来,增删改查就是对数组的一些最基本的操作的操作,但是这些操作由于普通的数组操作有所不同,我们来看看官方给出的解释:

在 JavaScript 中,数组只是另一种对象。同对象一样,你需要将 React state 中的数组视为只读的。这意味着你不应该使用类似于 arr[0] = ‘bird’ 这样的方式来重新分配数组中的元素,也不应该使用会直接修改原始数组的方法,例如 push() 和 pop()。

相反,每次要更新一个数组时,你需要把一个新的数组传入 state 的 setting 方法中。为此,你可以通过使用像 filter() 和 map() 这样不会直接修改原始值的方法,从原始数组生成一个新的数组。然后你就可以将 state 设置为这个新生成的数组。

下面是常见数组操作的参考表。当你操作 React state 中的数组时,你需要避免使用左列的方法,而首选右列的方法:

避免使用 (会改变原始数组)推荐使用 (会返回一个新数组)
添加元素pushunshiftconcat[...arr] 展开语法(例子)
删除元素popshiftsplicefilterslice(例子)
替换元素splicearr[i] = ... 赋值map(例子)
排序reversesort先将数组复制一份(例子)

以下为全部代码,我已标上了注释,不难应该能看懂:

import { useState, useEffect } from "react";
import "./App.css";

const tds = [
{ id: 1, content: "学习HTML", done: true },
{ id: 2, content: "学习CSS", done: false },
{ id: 3, content: "学习JavaScript", done: false },
];

function App() {
const [todos, setTodos] = useState(JSON.parse(localStorage.getItem('myreacttodos')) || []);// 存储待办事项
const [displayOption, setDisplayOption] = useState("all"); // 过滤待办事项的选项
const [newtodo, setNewTodo] = useState("");// 添加代办事项



useEffect(()=>{
    localStorage.setItem('myreacttodos',JSON.stringify(todos))
},[todos])

/**
* 添加ToDo
*/
function addToDo() {
    if (todos.length === 0) {
    // 数组为空的情况处理代码
    // 可以选择初始化一个默认值,例如:
    const newId = 1;
    console.log(newId);
    setTodos([{ id: newId, content: newtodo, done: false }]);
    setNewTodo("");
    } else {
    // 数组不为空的情况处理代码
    const newId = Math.max(...todos.map((t) => t.id)) + 1;
    console.log(newId);
    setTodos([...todos, { id: newId, content: newtodo, done: false }]);
    setNewTodo("");
    }
}

/**
* 按回车添加待办事项
* @param {input 键盘事件} e 
*/
function keyReturn(e) {
    if (e.keyCode === 13) {
    addToDo();
    }
}

/**
* 移除ToDo
*/
function removeToDo(id) {
    setTodos(todos.filter((t) => t.id !== id));
}

/**
* 更新ToDo
*/
function renewToDo(id, ck) {
    let newTodos = todos.map((t) =>
    t.id === id ? { ...t, done: ck === true ? true : false } : t
    );
    setTodos(newTodos);
}

// 处理按钮点击事件
const handleDisplayOption = (option) => {
    setDisplayOption(option);
};

// 根据选项过滤待办事项
const filteredTodos = todos.filter((todo) => {
    if (displayOption === "completed") {
    return todo.done;
    } else if (displayOption === "incomplete") {
    return !todo.done;
    } else {
    return true; // 显示所有事项
    }
});

return (
    <div className="container mx-auto max-w-xl p-4">
    <h1 className="text-3xl">ToDos</h1>
    <div>
        本项目依赖:
        <a className="link" src="https://react.docschina.org/" target="_blank">
        React
        </a>
        +
        <a className="link" src="https://cn.vitejs.dev/" target="_blank">
        Vite
        </a>
        +
        <a className="link" src="https://cn.vitejs.dev/" target="_blank">
        Tailwind CSS
        </a>
        +
        <a
        className="link"
        src="https://daisyui.com/docs/install/"
        target="_blank"
        >
        daisyUI
        </a>
    </div>
    <div className="p-4">
        <input
        value={newtodo}
        onChange={(e) => setNewTodo(e.target.value)}
        onKeyDown={(e) => {
            keyReturn(e);
        }}
        type="text"
        placeholder="输入代办事项后,按回车添加。"
        className="input input-bordered w-full input-md max-w-xs"
        />
        <button className="btn mx-4" onClick={addToDo}>
        添加代办事项
        </button>
    </div>
    <ul>
        {filteredTodos.map((todo) => (
        <li key={todo.id} className="flex gap-2">
            <div>
            <input
                onChange={(e) => renewToDo(todo.id, e.target.checked)}
                type="checkbox"
                checked={todo.done}
                className="checkbox"
                id={"todo" + todo.id}
            />
            <label
                className={todo.done ? "line-through" : ""}
                htmlFor={"todo" + todo.id}
            >
                {todo.id} - {todo.content}{" "}
            </label>
            </div>

            <button onClick={() => removeToDo(todo.id)} className="btn btn-sm">
            X
            </button>
        </li>
        ))}
    </ul>

    <div className="flex gap-2 mt-2">
        <button onClick={() => handleDisplayOption("all")} className="btn">
        显示所有
        </button>
        <button
        onClick={() => handleDisplayOption("completed")}
        className="btn"
        >
        已完成
        </button>
        <button
        onClick={() => handleDisplayOption("incomplete")}
        className="btn"
        >
        未完成
        </button>
    </div>
    <footer class="footer items-center p-4 text-neutral-content">
        <div class="items-center grid-flow-col">
        <svg
            width="36"
            height="36"
            viewBox="0 0 24 24"
            xmlns="http://www.w3.org/2000/svg"
            fill-rule="evenodd"
            clip-rule="evenodd"
            class="fill-current"
        >
            <path d="M22.672 15.226l-2.432.811.841 2.515c.33 1.019-.209 2.127-1.23 2.456-1.15.325-2.148-.321-2.463-1.226l-.84-2.518-5.013 1.677.84 2.517c.391 1.203-.434 2.542-1.831 2.542-.88 0-1.601-.564-1.86-1.314l-.842-2.516-2.431.809c-1.135.328-2.145-.317-2.463-1.229-.329-1.018.211-2.127 1.231-2.456l2.432-.809-1.621-4.823-2.432.808c-1.355.384-2.558-.59-2.558-1.839 0-.817.509-1.582 1.327-1.846l2.433-.809-.842-2.515c-.33-1.02.211-2.129 1.232-2.458 1.02-.329 2.13.209 2.461 1.229l.842 2.515 5.011-1.677-.839-2.517c-.403-1.238.484-2.553 1.843-2.553.819 0 1.585.509 1.85 1.326l.841 2.517 2.431-.81c1.02-.33 2.131.211 2.461 1.229.332 1.018-.21 2.126-1.23 2.456l-2.433.809 1.622 4.823 2.433-.809c1.242-.401 2.557.484 2.557 1.838 0 .819-.51 1.583-1.328 1.847m-8.992-6.428l-5.01 1.675 1.619 4.828 5.011-1.674-1.62-4.829z"></path>
        </svg>
        <p>Copyright © 2023 - All right reserved</p> <a className="link link-accent" src="https://suiyan.cc">My blog</a>
        </div>
    </footer>
    </div>
);
}

export default App;

总结

程序并没有做数据的持久保存,可以使用浏览器API:localStorage来保存待办事项的数组,这样下次打开浏览器就会显示之前保存的数据了,代码中已经更新添加了使用localStorage存储待办事项的存储代码。

另外,通过ToDo这个小项目分别使用vue和react编写,也算是对两大框架有了入门级的体验,总体来说,vue在学习过程中上手更为简单,适合从未接触过这类框架的新手来学习,如果你有不错的JavaScript和前端项目的编写经验,我还是推荐使用react,react更接近原生的写法,虽然没有太多的语法糖,但是兼容更简单,react官方文档写的太死板了,对新手不太友好,总之,这二个都是非常不错的前端框架,都值得去学习去使用。