【React入门实战】实现Todo代办

news2024/11/25 0:21:59

文章目录

    • 效果
    • 功能-状态管理
      • 相关接口定义
      • 相关方法定义
    • UI
      • input输入框:回车添加todo
      • 标题
      • 列表
      • 列表项
      • Main
    • 总体代码

非常简单入门的react-todo练习,代码写的很小白。

效果

技术栈:react-typeScript

  • 数据分为代办Todo已办完Done,可以点击复选框切换状态
  • 可以添加代办事件
  • 会用到useStateuseReducer,详情看状态管理 – React 中文文档

在这里插入图片描述
接下来是代码实现。

功能-状态管理

相关参考:
TypeScript中的标记联合类型:实现Todo代办-CSDN博客
迁移状态逻辑至 Reducer 中 – React 中文文档 (docschina.org)

相关接口定义

Todo的状态表示:

text表示代办内容,done表示是否完成,id表示它在列表中的位置。

interface Todo {
	readonly text: string;
	readonly done: boolean;
	readonly id: number;
}

对Todo的操作表示:

interface AddTodo {
	type: "Add_TODO";
	text: string;
}

interface ToggleTodo {
	type: "TOGGLE_TODO";
	index: number;
}

// 操作只有添加todo和修改todo两种
type TodoAction = AddTodo | ToggleTodo;

相关方法定义

操作Todo的方法:

// 点击修改状态
function todoReducer(list: Array<Todo>, action: TodoAction): Array<Todo> {
	switch (action.type) {
		case "Add_TODO": {
			return [
				...list,
				{
					text: action.text,
					done: false,
					id: list.length,
				},
			];
		}
		case "TOGGLE_TODO": {
			return list.map((item, index) => {
				if (index !== action.index) {
					return item;
				}

				return {
					text: item.text,
					done: !item.done,
					id: item.id,
				};
			});
		}

		default: {
			return list;
		}
	}
}

useReducer部分:写在比较父级的组件中。把对应方法用prop的方式传给需要用的子组件。此博客写在了Main组件中。

// useReducer
const [todoList, dispatch] = useReducer(todoReducer, initTodo);

function handleAddTodo(text: string) {
	dispatch({
		type: "Add_TODO",
		text: text,
	});
}

function handleToggleTodo(index: number) {
	dispatch({
		type: "TOGGLE_TODO",
		index: index,
	});
}

模拟的数据:initTodo

// 模拟数据
const initTodo: Array<Todo> = [
	{
		text: "吃饭",
		done: true,
		id: 0,
	},
	{
		text: "睡觉",
		done: true,
		id: 1,
	},
	{
		text: "上班",
		done: true,
		id: 2,
	},
	{
		text: "下班",
		done: false,
		id: 3,
	},
	{
		text: "运动",
		done: false,
		id: 4,
	},
	{
		text: "听歌",
		done: false,
		id: 5,
	},
];

UI

react是非常组件化的框架。此Todo可以拆成好几个组件:

  • input输入框:回车添加todo
  • 标题
  • 列表:分开显示Todo/Done的列表
  • 列表项

input输入框:回车添加todo

这里需要用useState管理input输入的状态。

注意:每个input框都要绑定onChange或readonly,否则会报错。

当回车时,添加输入框中的值到Todo的列表,即触发前面定义的handleAddTodo方法。此方法在这里没有定义,因此要从定义它的地方(Main)传过来。

function Add({ handleAddTodo }: { handleAddTodo: Function }) {
	const [inputValue, setInputValue] = useState("");
	return (
		<>
			<div className="header">
				<input
					type="text"
					value={inputValue}
					onChange={(e) => {
						setInputValue(e.target.value);
					}}
					onKeyDown={(e) => {
						if (e.key === "Enter") {
							handleAddTodo(inputValue);
							setInputValue("");
						}
					}}
					placeholder="在这里添加新的代办事件"
				/>
			</div>
		</>
	);
}

标题

// 标题
function ShowTitle({ title }: { title: string }) {
	return (
		<>
			<h2>{title}</h2>
		</>
	);
}

列表

  • todoList是reduce中管理的所有事项的列表。
  • done表示当前列表是代办(false)还是已完成(true)
  • handleToggleTodo是点击复选框更改列表项状态的方法
// 展示todo的列表
function ShowList({
	todoList,
	done,
	handleToggleTodo,
}: {
	todoList: Array<Todo>;
	done: boolean;
	handleToggleTodo: Function;
}) {
	const data = todoList.filter((item) => {
		return item.done === done;
	});

	const show = data.map((item) => {
		return (
			<ListItem
				key={item.id}
				item={item}
				handleToggleTodo={handleToggleTodo}
			></ListItem>
		);
	});
	return <>{show}</>;
}

列表项

// list的每一项
function ListItem({
	item,
	handleToggleTodo,
}: {
	item: Todo;
	handleToggleTodo: Function;
}) {
	return (
		<div className="item">
			<input
				type="checkbox"
				checked={item.done}
				onChange={() => {
					handleToggleTodo(item.id);
				}}
				name=""
				id=""
			/>
			{item.text}
		</div>
	);
}

Main

function Main() {
	// useReducer
	const [todoList, dispatch] = useReducer(todoReducer, initTodo);

	function handleAddTodo(text: string) {
		dispatch({
			type: "Add_TODO",
			text: text,
		});
	}

	function handleToggleTodo(index: number) {
		dispatch({
			type: "TOGGLE_TODO",
			index: index,
		});
	}

	return (
		<>
			<Add handleAddTodo={handleAddTodo}></Add>
			<ShowTitle title={"Todo"}></ShowTitle>
			<ShowList
				todoList={todoList}
				done={false}
				handleToggleTodo={handleToggleTodo}
			></ShowList>
			<ShowTitle title={"Done"}></ShowTitle>
			<ShowList
				todoList={todoList}
				done={true}
				handleToggleTodo={handleToggleTodo}
			></ShowList>
		</>
	);
}

总体代码

import { useState, useReducer } from "react";

// 标题
function ShowTitle({ title }: { title: string }) {
	return (
		<>
			<h2>{title}</h2>
		</>
	);
}

// 添加todo的输入框
function Add({ handleAddTodo }: { handleAddTodo: Function }) {
	const [inputValue, setInputValue] = useState("");
	return (
		<>
			<div className="header">
				<input
					type="text"
					value={inputValue}
					onChange={(e) => {
						setInputValue(e.target.value);
					}}
					onKeyDown={(e) => {
						if (e.key === "Enter") {
							handleAddTodo(inputValue);
							setInputValue("");
						}
					}}
					placeholder="在这里添加新的代办事件"
				/>
			</div>
		</>
	);
}

// list的每一项
function ListItem({
	item,
	handleToggleTodo,
}: {
	item: Todo;
	handleToggleTodo: Function;
}) {
	return (
		<div className="item">
			<input
				type="checkbox"
				checked={item.done}
				onChange={() => {
					handleToggleTodo(item.id);
				}}
				name=""
				id=""
			/>
			{item.text}
		</div>
	);
}

// 展示todo的列表
function ShowList({
	todoList,
	done,
	handleToggleTodo,
}: {
	todoList: Array<Todo>;
	done: boolean;
	handleToggleTodo: Function;
}) {
	const data = todoList.filter((item) => {
		return item.done === done;
	});

	const show = data.map((item) => {
		return (
			<ListItem
				key={item.id}
				item={item}
				handleToggleTodo={handleToggleTodo}
			></ListItem>
		);
	});
	return <>{show}</>;
}

function Main() {
	// useReducer
	const [todoList, dispatch] = useReducer(todoReducer, initTodo);

	function handleAddTodo(text: string) {
		dispatch({
			type: "Add_TODO",
			text: text,
		});
	}

	function handleToggleTodo(index: number) {
		dispatch({
			type: "TOGGLE_TODO",
			index: index,
		});
	}

	return (
		<>
			<Add handleAddTodo={handleAddTodo}></Add>

			<ShowTitle title={"Todo"}></ShowTitle>
			<ShowList
				todoList={todoList}
				done={false}
				handleToggleTodo={handleToggleTodo}
			></ShowList>
			<ShowTitle title={"Done"}></ShowTitle>
			<ShowList
				todoList={todoList}
				done={true}
				handleToggleTodo={handleToggleTodo}
			></ShowList>
		</>
	);
}

function App() {
	return (
		<>
			<div className="main">
				<Main></Main>
			</div>
		</>
	);
}

interface Todo {
	readonly text: string;
	readonly done: boolean;
	readonly id: number;
}

interface AddTodo {
	type: "Add_TODO";
	text: string;
}

interface ToggleTodo {
	type: "TOGGLE_TODO";
	index: number;
}

// 操作只有添加todo和修改todo两种
type TodoAction = AddTodo | ToggleTodo;

// 点击修改状态
function todoReducer(list: Array<Todo>, action: TodoAction): Array<Todo> {
	switch (action.type) {
		case "Add_TODO": {
			return [
				...list,
				{
					text: action.text,
					done: false,
					id: list.length,
				},
			];
		}
		case "TOGGLE_TODO": {
			return list.map((item, index) => {
				if (index !== action.index) {
					return item;
				}

				return {
					text: item.text,
					done: !item.done,
					id: item.id,
				};
			});
		}

		default: {
			return list;
		}
	}
}

// 模拟数据
const initTodo: Array<Todo> = [
	{
		text: "吃饭",
		done: true,
		id: 0,
	},
	{
		text: "睡觉",
		done: true,
		id: 1,
	},
	{
		text: "上班",
		done: true,
		id: 2,
	},
	{
		text: "下班",
		done: false,
		id: 3,
	},
	{
		text: "运动",
		done: false,
		id: 4,
	},
	{
		text: "听歌",
		done: false,
		id: 5,
	},
];

export default App;

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

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

相关文章

C#,数值计算——函数计算,Dfridr的计算方法与源程序

1 文本格式 using System; namespace Legalsoft.Truffer { /// <summary> /// 通过Ridders的多项式外推方法返回函数func在点x处的导数。 /// 输入值h作为估计的初始步长&#xff1b;它不需要很小&#xff0c;而是应为x上的增量&#xff0c; /// 在此增…

springboot,spring框架返回204 status code的时候,会吞掉返回值

背景 发现有个有意思的现象&#xff0c;就是当你的接口返回204的 HTTP status code 的时候&#xff0c;会自动把 response body 吃掉&#xff0c;即使代码里是有返回的。例如 &#xff08;其实204本身就是NO_CONTENT的意思&#xff0c;不过我是真没想到真干掉了返回&#xff0…

Spring6学习笔记01

一、课程简介 Spring框架是一款极其优秀的轻量级开源框架&#xff0c;为了解决企业应用开发的复杂性而出现。Spring框架的用途不仅仅限于服务器端的开发&#xff0c;从简单性、可测试性和松耦合性角度而言&#xff0c;绝大部分Java应用都可以从Spring中受益。Spring框架凭借其…

Linux Hadoop平台伪分布式安装

Linux Hadoop 伪分布式安装 1. JDK2. Hadoop3. MysqlHive3.1 Mysql8安装3.2 Hive安装 4. Spark4.1 Maven安装4.2 Scala安装4.3 Spark编译并安装 5. Zookeeper6. HBase 版本概要&#xff1a; jdk&#xff1a; jdk-8u391-linux-x64.tar.gzhadoop&#xff1a;hadoop-3.3.1.tar.gzh…

JVM在线分析-解决问题的工具一(jinfo,jmap,jstack)

1. jinfo (base) PS C:\Users\zishi\Desktop> jinfo Usage:jinfo <option> <pid>(to connect to a running process)where <option> is one of:-flag <name> to print the value of the named VM flag #输出对应名称的参数-flag [|-]<n…

v-calendar 日历组件使用自定义提示内容

目录 0.介绍 1.安装v-calendar 2.页面使用 3.使用插槽实现待办数量的标记 0.介绍 最近项目中用到了日历插件&#xff0c;需要统计每天的任务数量&#xff0c;类似elementui的badge组件&#xff0c;待办任务数量 大概最后的效果如下图所示&#xff0c;右上角把代办任务数量…

php 二分查询算法实现

原理&#xff1a;二分查找算法&#xff08;Binary Search&#xff09;是一种针对有序数组的查找算法。它的原理是通过将查找区间逐渐缩小一半来快速定位要查找的目标值。 应用场景&#xff1a; 数据库或文件系统索引查找&#xff1a;在数据库或文件系统中&#xff0c;索引是有…

基于springboot 停车场管理系统-计算机毕设 附源码 39315

spring boot停车场管理系统的设计与实现 摘 要 科技进步的飞速发展引起人们日常生活的巨大变化&#xff0c;电子信息技术的飞速发展使得电子信息技术的各个领域的应用水平得到普及和应用。信息时代的到来已成为不可阻挡的时尚潮流&#xff0c;人类发展的历史正进入一个新时代。…

【C++数据结构】顺序存储结构的抽象实现

文章目录 前言一、目标二、SeqList实现要点三、SeqList函数实现3.1 get函数3.2 set函数3.3 insert函数带2个参数的insert带一个参数的insert 3.4 remove函数3.5 clear函数3.6 下标运算符重载函数无const版本const版本 3.7 length函数 总结 前言 当谈到C数据结构时&#xff0c;…

97 只出现一次的数字

只出现一次的数字 题解1 异或的应用&#xff08;判断出现次数是奇偶&#xff09; 给你一个 非空 整数数组 nums &#xff0c;除了某个元素只出现一次以外&#xff0c;其余每个元素均出现两次。找出那个只出现了一次的元素。 你必须设计并实现线性时间复杂度的算法来解决此问题…

PCIe寄存器之二

关键字索引&#xff1a; CAP_PM 对应&#xff1a;Capabilities: [c0] Power Management CAP_MSI 对应&#xff1a;Capabilities: [c8] MSI CAP_MSIX对应&#xff1a;Capabilities: [e0] MSI-X CAP_EXP 对应&#xff1a;Capabilities: [70] Express (v2) Endpoint 以上 [] 内的…

开设自己的网站系类03安装数据库(centos版)

编者买了一个服务器打算自己构建一个网站&#xff0c;用于记录生活。网站大概算是一个个人博客吧。记录创建过程的一些步骤。 前面已经讲过配置服务器的程序运行环境 网站运行还需要数据库&#xff0c;本篇文章则是安装数据库的内容。 卸载mariadb 查看是否有安装 mariadb&…

【Python】数据分析案例:世界杯数据可视化

文章目录 前期数据准备导入数据 分析&#xff1a;世界杯中各队赢得的比赛数分析&#xff1a;先打或后打的比赛获胜次数分析&#xff1a;世界杯中的抛硬币决策分析&#xff1a;2022年T20世界杯的最高得分者分析&#xff1a;世界杯比赛最佳球员奖分析&#xff1a;最适合先击球或追…

【C语言基础】近期所学到的函数以及关键字(函数memset、scanf、关键字staric、 inline、volatile)

&#x1f4e2;&#xff1a;如果你也对机器人、人工智能感兴趣&#xff0c;看来我们志同道合✨ &#x1f4e2;&#xff1a;不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】 &#x1f4e2;&#xff1a;文章若有幸对你有帮助&#xff0c;可点赞 &#x1f44d;…

python核心编程速记【笔记迁移】

笔记速记 1.python非常注重缩进&#xff0c;这是它的显著特征之一。 2.import相当于头文件声明模块。 3.利用type函数 type(a)可以查看当前变量类型。 isinstance可以比较两个数据类型并返回一个布尔值。 4.这里面的可直接使用and和or作为一个函数 5.python的算法比较贴合…

如何改善食品饮料包装生产企业的OEE?

食品饮料这类商品在我们的日常生活中十分常见&#xff0c;它们存在于各类商店、超市或路边的小店里。而食品饮料的包装是吸引人们购买该产品的一个重要因素。为了在这个市场中脱颖而出并提高盈利能力&#xff0c;企业需要关注设备的综合效率&#xff0c;即OEE&#xff08;Overa…

SpringBoot测试类启动web环境-上篇

1.坐标修改 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency> 2.测试类测试 说明&#xff1a;SpringBootTest()中的webEnvironment值的说明&#xff1b; 2.1不启…

vue项目js原生属性IntersectionObserver实现图片懒加载

vue项目js原生属性IntersectionObserver实现图片懒加载 IntersectionObserver 使用js原生属性IntersectionObserver实现观察img元素是否处于游览器视口中 懒加载原理&#xff1a;给img设置一个默认url图片&#xff0c;观察图片处于视口内以后&#xff0c;动态改变img的url为自己…

机组 CPU

控制器&#xff1a;协调并控制计算机各部件执行程序的指令序列&#xff0c;其基本功能是取指令、分析指令和执行指令 功能 CPU 必须具有控制程序的顺序执行&#xff08;指令控制&#xff09;、产生完成每条指令所需的控制命令&#xff08;操作控制&#xff09;、对各种操作加…

原神游戏干货分享:探索璃月的宝箱秘密,提高游戏资源获取效率!

《原神》是一款备受玩家喜爱的开放世界冒险游戏&#xff0c;而在游戏中获取资源是提升角色实力的重要途径。在这篇实用干货分享中&#xff0c;我们将介绍一些探索璃月地区的宝箱秘密&#xff0c;帮助你提高游戏资源获取的效率。 首先&#xff0c;璃月地区的宝箱分为普通宝箱和精…