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

文章目录

    • 效果
    • 功能-状态管理
      • 相关接口定义
      • 相关方法定义
    • 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;

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

西门子S7-1200PLC混合通信编程(ModbusTcp和UDP通信)

S7-1200PLC的MODBUS-TCP通信 西门子PLC ModbusTcp通信访问网关后从站(SCL语言轮询状态机)-CSDN博客文章浏览阅读305次。西门子PLC的ModbusTcp通信在专栏已有很多文章介绍,所不同的是每个项目的通信需求都略有不同,今天我们以访问网关后的三个从站数据来举例,给出轮询的推荐…

WPS的JS宏基础(一)

基础知识 1、简单的第一个宏 //注意function只能全部用小写 function demo(){alert("你好!") }2、录制宏生成工资条 function 使用录制宏自动生成代码以JS宏为例()//使用相对引用 {Selection.Copy(undefined);ActiveCell.Offset(5, 0).Range("A1:M4").I…

Java进击框架:Spring-数据存取(七)

Java进击框架&#xff1a;Spring-数据存取&#xff08;七&#xff09; 前言事务管理声明式事务管理 DAO支持JDBC的数据访问使用JdbcTemplate控制数据库连接JDBC批处理操作封装 SQL 语句中的参数 使用R2DBC进行数据访问对象关系映射(ORM)数据访问HibernateJPA XML模式 前言 参考…

【免费送书】写博客模板

【点我-这里送书】 本人详解 作者&#xff1a;王文峰&#xff0c;参加过 CSDN 2020年度博客之星&#xff0c;《Java王大师王天师》 公众号&#xff1a;JAVA开发王大师&#xff0c;专注于天道酬勤的 Java 开发问题中国国学、传统文化和代码爱好者的程序人生&#xff0c;期待你的…

如何优化负载均衡?一文讲懂

当web应用程序增长到单服务器无法承受的地步&#xff0c;企业就面临着优化负载均衡的需求。简而言之&#xff0c;企业需要实现流量重定向&#xff0c;就需要从业务可靠性的需求出发&#xff0c;寻找一套可行的负载均衡方案&#xff0c;那么常用的负载均衡方案有哪些&#xff1f…

UnoCSS框架常用语法

文章目录 🍉vscode 开发插件🍉设置边框颜色🍉设置宽、高、背景色、外边距🍉设置flex🍉设置元素在滚动时固定在指定区域内🍉vscode 开发插件 vscode 开发建议安装 UnoCSS插件 🍉设置边框颜色 border-[color]: 设置边框的颜色,[color]可以是预设的颜色名称(如…

什么是 eCPM?它与 CPM 有何不同?

目录 eCPM 什么是 eCPM&#xff1f;它与 CPM 有何不同&#xff1f; 如何计算 eCPM&#xff1f; 该指标的主要优势有哪些&#xff1f; eCPM 底价 eCPM 达到多少比较合适&#xff1f; eCPM 每千人有效成本 (eCPM) 是指发行商&#xff08;App 开发者&#xff09;在 App 中每…

境电商为什么要做独立站?API一键对接秒上架瞬间拥有全平台几十亿商品和用户!

境电商为什么要做独立站&#xff1f;它的优势又有哪一些&#xff1f; 如果说我们的企业是做b two b的跨境电商&#xff0c;那今天这个内容一定要仔细&#xff0c;API一键对接秒上架瞬间拥有全平台几十亿商品和用户&#xff01; 第一呢&#xff0c;独立站它就是我们自己做的一个…

Linux入门(二)

Linux入门&#xff08;二&#xff09; 1&#xff1a;创建文件 1.1 touch命令 使用touch命令在文件不存在时&#xff0c;会创建文件。同时不支持在创建文件时&#xff0c;写入一些内容&#xff0c;该文件的大小是0kb. touch test.txt 注意&#xff0c;无法创建多级目录文件 …

redisson中的分布式锁

文章目录 redisson中的分布式锁可重入锁&#xff08;Reentrant Lock&#xff09; redisson中的分布式锁 ​ Redisson是一个在Redis的基础上实现的Java驻内存数据网格&#xff08;In-Memory Data Grid&#xff09;。它不仅提供了一系列的分布式的Java常用对象&#xff0c;还提供…

力扣每日一题 ---- 2906. 构造乘积矩阵

这题很简单(一下就能想到是前缀和的提米)&#xff0c;但是在处理12345上面需要仔细一点&#xff0c;本来我最开始想到的时候全部累乘在除掉当前数&#xff0c;但是这样就没有把12345考虑进去&#xff0c;如果他本身是12345的话&#xff0c;那么除他以外的乘积并不一定是0&#…

ubuntu22.04桌面版系统无法识别USB摄像头

虚拟机连接电脑摄像头连接失败&#xff08;驱动程序错误&#xff09; 本文为转载&#xff1a;版权归远作者所有&#xff0c;之所以转载是为了避免被原作者删除 巴黎铁塔下的女孩 你尽管努力&#xff0c;剩下的交给时间 虚拟机调用电脑的摄像头&#xff0c;正常情况下只需点击…

鲁大师10月新机性能/流畅/久用榜:骁龙8 Gen3一鸣惊人,双十一“6系”处理器成井喷状态

刚刚过去的10月份手机圈可谓是热闹纷呈,要数量有数量,要新品有新品,要旗舰有旗舰,要走量也有走量。10月份的大部分光芒,毫无疑问都将被骁龙8 Gen3以及重夺骁龙旗舰首发的小米 14系列身上。 骁龙8 Gen3毫无疑问,代表着骁龙旗舰处理器的又一个巅峰,从目前鲁大师后台抓取到的数据…

递归下降语法分析程序设计与实现

制作一个简单的C语言词法分析程序_用c语言编写词法分析程序-CSDN博客文章浏览阅读276次。C语言的程序中&#xff0c;有很单词多符号和保留字。一些单词符号还有对应的左线性文法。所以我们需要先做出一个单词字符表&#xff0c;给出对应的识别码&#xff0c;然后跟据对应的表格…

基于单片机的土壤温湿度控制系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 技术交流认准下方 CSDN 官方提供的联系方式 文章目录 概要 一、温湿度控制系统的整体规划2.3系统的总体构架 二、温度湿度控制系统硬件设计3.1系统硬件概述 三、 温湿度系统软件…

Redis学习(十)RedisTemplate 对各种数据类型的支持

目录 一、SpringDataRedis 简介1.1 什么是 Redis&#xff1f;1.2 什么是 Jedis&#xff1f;1.3 什么是 Spring Data Redis&#xff1f; 二、RedisTemplate 中 API 使用2.1 pom.xml 依赖2.2 配置文件2.3 RedisTemplate 的直接方法2.4 String 类型相关操作2.5 Hash 类型相关操作2…

APP安全测试详解

在工作过程中&#xff0c;我接触到了一些SDL安全提测的工作。原来我是学web端渗透比较多的&#xff0c;移动端这块基本没怎么试过手&#xff0c;结果刚开始一直踩坑&#xff0c;连抓包都抓不到(&#xff34;▽&#xff34;)。 下面记录下我遇到的部分问题和解决方法&#xff0…

《QT从基础到进阶·十八》QT中的各种鼠标事件QEvent

1、界面标题栏事件&#xff1a; NonClientAreaMouseButtonPress 标题栏点击事件 NonClientAreaMouseButtonRelease 标题栏释放事件 bool CustomPopDialog::event(QEvent* event) {switch (event->type()){case QEvent::MouseButtonRelease://Event of mouse releasing wind…

Python爬虫抓取微博数据及热度预测

首先我们需要安装 requests 和 BeautifulSoup 库&#xff0c;可以使用以下命令进行安装&#xff1a; pip install requests pip install beautifulsoup4然后&#xff0c;我们需要导入 requests 和 BeautifulSoup 库&#xff1a; import requests from bs4 import BeautifulSou…

奇异矩阵、非奇异矩阵

对于一个方阵A&#xff1a; 如果A的行列式等于0&#xff0c;称矩阵A为奇异矩阵如果A的行列式不等于0&#xff0c;称A 非奇异矩阵 也就是说&#xff0c;对于方阵A&#xff0c;如果它是满秩的&#xff0c;即它的秩等于矩阵的阶数&#xff0c;就是非奇异矩阵&#xff1b;如果秩小…