【Typescript学习】使用 React 和 TypeScript 构建web应用(四)useReducer、扑街了的分区功能【完结了】

news2025/1/4 19:30:58

教程来自freecodeCamp:【英字】使用 React 和 TypeScript 构建应用程序
跟做,仅记录用
其他资料:https://www.freecodecamp.org/chinese/news/learn-typescript-beginners-guide/
作者提供的源码https://github.com/piyush-eon/react-typescript-taskify/tree/react-typescript-tutorial


第四天

以下是视频(1:00-1:20) 的内容

1 useReducer

这part的代码是我自己写的,因为原视频中说作为homework,就没给代码

对todo内容的增删改查进行逻辑整合,写一个reducer
state 即为todo数组
action有四种: add、remove、done、edit
改造成reducer

  1. 先定义针对todos的reducer函数TodoReducer,以及Actions类型
    model.ts
// ......
export type Actions = 
    { type: 'add', payload: string } 
  | { type: 'remove', payload: number } 
  | { type: 'done', payload: number }
  | { type: 'edit', payloadId: number, payloadContent: string}

export const TodoReducer = (state: Todo[], action: Actions) => {
 switch (action.type) {
    case 'add':
        return [
          ...state,
          { id: Date.now(), todo: action.payload, isDone: false }
        ];
    case 'remove':
        return state.filter((todo) => todo.id !== action.payload);
    case 'done':
        return state.map((todo) => todo.id === action.payload 
            ? {...todo, isDone: !todo.isDone}
            : todo
        )
    case 'edit':
        return state.map((todo) => (
            todo.id === action.payloadId
            ? {...todo, todo: action.payloadContent }
            : todo
        ))
    default:
        return state;
 }
}
  1. 其次修改 App.tsx,用useReducer替换useState,修改handleAdd以及向子组件的传值
import React, { useState, useReducer } from 'react';
import './App.css';
import InputField from './components/InputField';
import TodoList from './components/TodoList';
import { TodoReducer } from "./model";

const App: React.FC = () => {
  const [todo, setTodo] = useState<string>(""); // 尖括号加上变量类型
  const [todosState, dispatch] = useReducer(TodoReducer, []);
  
  
  return (
    <div className="App">
      <span className='heading'>Taskify</span>
      <InputField todo={todo} setTodo={setTodo} todosDispatch={dispatch}/>
      <TodoList todosState={todosState} todosDispatch={dispatch}/>
    </div>
  );
}

export default App;
}
  1. 在子组件中使用dispatch函数,先看‘add’这个action的调用,即InputField.tsx
// ...
type Props = {
    todo: string,
    setTodo: React.Dispatch<React.SetStateAction<string>>,
    todosDispatch: React.Dispatch<Actions>,
}

const InputField: React.FC<Props> = ({todo, setTodo, todosDispatch}: Props) => {
  const inputRef = useRef<HTMLInputElement>(null);
  // 点击GO后
  const handleAdd = (e: React.FormEvent):void => {
    e.preventDefault(); // 取消默认的页面刷新行为
    if(todo) {
      todosDispatch({type: 'add', payload: todo})
      setTodo("");
    }
  };
  return (
    <form className='input' onSubmit={(e) => {
            handleAdd(e);
            console.log(e);
            inputRef.current?.blur();  // 移除focus状态
        }}
    >
        <input type="input"
          ref={inputRef}
          value={todo} 
          onChange={
            (e)=>setTodo(e.target.value)
          }
          placeholder="Enter a task" 
          className='input__box'
        />
        <button className='input_submit' type='submit'>
            GO
        </button>
    </form>
  )
}
  1. 再修改使用done、remove、edid的SingleTodo.tsx
type Props = {
    todo: Todo,
    todosDispatch: React.Dispatch<Actions>
}

const SingleTodo = ({todo, todosDispatch}: Props) => {
  const [edit, setEdit] = useState<boolean>(false);
  const [editTodo, setEditTodo] = useState<string>(todo.todo);
  // done按钮的响应
  const handleDone = (id: number) => {
    todosDispatch({
      type: 'done',
      payload: id
    })
  };
  // edit按钮的响应
  const handleEdit = (e:React.FormEvent, id: number) => {
    e.preventDefault();  // 禁止默认的页面刷新行为
    todosDispatch({
      type:'edit',
      payloadContent: editTodo,
      payloadId: id
    })
    setEdit(false);
  }
  // delete按钮的响应
  const handleDelete = (id: number ) => {
    todosDispatch({
      type: 'remove', 
      payload: id
    })
  };
  
  const inputRef = useRef<HTMLInputElement>(null);  // 编辑框
  // edit状态改变时自动获取编辑框的焦点
  useEffect(() => {  
    inputRef.current?.focus();
  }, [edit]);
  
  // ...
  
}

至此,完成了基础版的TASKIFY
在这里插入图片描述

2 增加分区功能

我们进一步完善,期望将进行中的任务和已完成的任务分区显示
在这里插入图片描述
更改TodoList.tsx中的HTML结构

const TodoList:React.FC<Props> = ({todosState, todosDispatch}: Props) => {
  return (
    <div className="container">
      <div className='todos'>
        <span className="todos__heading">
          Active Tasks
        </span>
        {
          todosState.map(todo =>(
            <SingleTodo key={todo.id}
              todo={todo}  
              todosDispatch={todosDispatch}
            />
        ))}
      </div>
      <div className='todos remove'>
        <span className="todos__heading">
          Completed Tasks
        </span>
        {todosState.map(todo =>(
            <SingleTodo key={todo.id}
                todo={todo}  
                todosDispatch={todosDispatch}
            />
        ))}
      </div>
    </div>
  )
}

修改样式 styles.css

.input {
    display: flex;
    width: 95%;
    position: relative;
    align-items: center;
}
.input__box {
    width: 100%;
    border-radius: 50px;
    padding: 20px 30px;
    font-size: 25px;
    border: none;
    transition: 0.2s;
    box-shadow: inset 0 0 5px black;
}

.input__box:focus {
    box-shadow: 0 0 10px 1000px rgba(0, 0, 0, 0.5);
    outline: none;
}

.input_submit {
    position: absolute;
    border-radius: 50%;
    font-size: 15px;
    margin: 12px;
    right: 0px;
    background-color: #2f74c0;
    color: white;
    width: 50px;
    height: 50px;
    border: none;
    box-shadow: 0 0 10px black;
    transition: 0.2s all;
}
.input_submit:hover {
    background-color: #388ae2;
}
/* 按钮点击时 */
.input_submit:active {  
    transform: scale(0.8);  /* 缩放 */
    box-shadow: 0 0 5px black;
}

.container {
    display: flex;
    width: 95%;
    margin-top: 10px;
    align-items: flex-start;
    justify-content: space-between;
}

.todos {
    display: flex;
    
    width: 47.5%;
    flex-direction: column;
    padding: 15px;
    border-radius: 5px;
    background-color: rgb(50, 195, 205);
}

.todos__heading {
    font-size: 20px;
    color: white;

}
.todos__single {
    display: flex;
    border-radius: 5px;
    padding: 20px;
    margin-top: 15px;
    background-image: url("https://img.freepik.com/free-photo/crumpled-yellow-paper-background-close-up_60487-2390.jpg?size=626&ext=jpg");
    transition: 0.2s;
}
.todos__single:hover {
    box-shadow: 0 0 5px black;
    transform: scale(1.03);
}
.todos__single--text {
    flex: 1;
    padding: 5px;
    border: none;
    font-size: 20px;
}
.todos__single--textJ:focus {
    outline: none;
}

.icon {
    margin-left: 10px;
    font-size: 25px;
    cursor: pointer;
}

@media (max-width: 1100px){
    .todos {
        width: 45%;
    }
}
@media (max-width: 700px) {
    .input {
        width: 95%;
    }
    .todos {
        width: 95%;
        margin-bottom: 10px;
    }
    .container {
        width: 95%;
        flex-direction: column;
    }
}
.remove {
    background-color: rgb(235, 103, 80);
}

App.tsx中为TodoList组件传入completedTodos属性

     <TodoList 
        todosState={todosState} 
        todosDispatch={dispatch}
        completedTodos={completedTodos}
        setCompletedTodos={setCompletedTodos}
      />

3 添加两个列表间的拖拽功能

借助第三方包 react-beautiful-dnd

ps: 在TypeScript中安装一些依赖时,需要安装types版本,注意不要安装成js包了

npm install --save @types/react-beautiful-dnd

… 得,这个依赖我整不好了,应该是各依赖版本间兼容的问题,总是报错。
具体这个依赖的使用,官方也有详细教程,之后再看吧…


总结

今天主要是useReducer的使用。react-beautiful-dnd那个包可气死我了,以后再说吧。
这个小项目就结束了,主要是为了熟悉一下TypeScript,顺便复习React和CSS,还留了个小坑
视频作者提供了项目源码,供学习https://github.com/piyush-eon/react-typescript-taskify/tree/react-typescript-tutorial

本博仅做记录,如有问题,都是我的错,我改正

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

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

相关文章

机器学习【西瓜书/南瓜书】--- 第四章决策树

一、决策树理论分析 1.1 通俗理解 决策树是一种非常经典的机器学习算法&#xff0c;通俗理解的话我们可以举一个例子&#xff0c;比如现在别人要找你借钱&#xff0c;那么按照首先是不是要判断你和他的关系如何?如果关系不好&#xff0c;我就直接拒绝他。如果关系很好&#…

Python机器学习:一元回归

→\rightarrow→回归效果评价 &#x1f315; 一元回归 一元回归主要研究一个自变量和一个因变量之间的关系&#xff0c;而这个自变量和因变量之间的关系又可分为线性回归和非线性回归。 ⭐️ 一元线性回归分析两个变量之间的线性关系&#xff0c;如ykxbykxbykxb中xxx和yyy就是…

深度学习笔记:神经网络的学习(1)

机器学习的核心在于从数据中提取规律和特征&#xff0c;并用于分类或预测。对于识别手写数字&#xff0c;如果人工设计一个识别算法逻辑是十分困难的。一种方法是任务在数据中提取更重要的特征量&#xff0c;然后利用机器学习算法如SVM或KNN。而神经网络的方法则是完全由机器自…

ISIS的3级别(level-1、level-2、level-1-2)4大类(IIH、LSP、CSNP、PSNP)9小类与邻接关系建立LSP交互过程介绍

2.2.0 ISIS 4种报文类型IIH、LSP、CSNP、PSNP、邻居建立过程、交互LSP过程 ISIS的3级别4大类9小类 ISIS拥有3种级别的路由器&#xff0c;分别是level-1、level-2、level-1-2。 不同级别之间进行交互的报文也是有所区别的&#xff0c;常规的ISIS报文分有4大类&#xff1a;IIH、…

cubeIDE开发, stm32人工智能开发应用实践(Cube.AI).篇一

一、cube.AI简介及cubeIDE集成 1.1 cube.AI介绍 cube.AI准确来说是STM32Cube.AI&#xff0c;它是ST公司的打造的STM32Cube生态体系的扩展包X-CUBE-AI&#xff0c;专用于帮助开发者实现人工智能开发。确切地说&#xff0c;是将基于各种人工智能开发框架训练出来的算法模型&#…

Vue3商店后台管理系统设计文稿篇(六)

记录使用vscode构建Vue3商店后台管理系统&#xff0c;这是第六篇&#xff0c;从这一篇章开始&#xff0c;所有的预备工作结束&#xff0c;正式进入商店后台管理系统的开发 文章目录一、创建后台管理系统的标题栏二、安装Icon 图标三、创建Menu菜单正文内容&#xff1a; 一、创…

PowerShell 学习笔记:操作JSON文件

JSON文件&#xff08;字符串&#xff09;是有一定格式要求的文本文件。百度百科JSON&#xff08;JavaScriptObject Notation, JS对象简谱&#xff09;是一种轻量级的数据交换格式。它基于 ECMAScript&#xff08;European Computer Manufacturers Association, 欧洲计算机协会制…

初识Linux常见指令汇总

文章目录前言1.对文件或目录的常用指令1.查看当前路径下的文件或目录相关信息2.进入指定路径3.创建删除文件或者目录4.使用nano简单编辑文件查看文件属性5.复制移动重命名文件或目录6.输入输出重定(查看文件内容)向和搜索查找1.输入输出重定向2.搜索查找7.打包压缩文件2.时间相…

如何使用Maven构建Java项目?Maven的使用详细解读

文章目录1. 前言2. Maven 快速入门2.1 Maven 项目模型2.2 Maven 仓库3. Maven的安装配置3.1 安装3.2 配置环境变量3.4 Maven 配置4. Maven 的常用命令4.1 编译4.2 清理4.3 打包4.4 测试4.5 安装5. Maven生命周期6. 总结Java编程基础教程系列&#xff1a;1. 前言 在 Java 开发中…

C++初阶:list类

文章目录1 list介绍2 list的模拟实现2.1 类的定义2.2 默认成员函数2.2.1 构造函数2.2.2 析构函数2.2.3 拷贝构造2.2.4 赋值重载2.3 迭代器2.3.1 正向迭代器2.3.2 反向迭代器2.4 修改接口2.4.1 任意位置插入2.4.2 任意位置删除2.5 其他接口2.5.1 尾插2.5.2 头插2.5.3 尾删2.5.3 …

3.7-2动态规划--图像压缩(举例子和写代码)

3.7动态规划--图像压缩_昵称什么的不存在的博客-CSDN博客 问题描述&#xff08;再写一遍&#xff09; 这篇文章是接着上面这一篇写的&#xff0c;就是写一个例子方便理解&#xff0c;模拟填写数组的过程 l: l[i]存放第i段长度, 表中各项均为8位长&#xff0c;限制了相同位数的…

CGAL 点云精配准之ICP算法

文章目录 一、简介二、相关参数三、实现过程三、举个栗子四、实现效果参考资料一、简介 ICP算法总共分为6个阶段,如下图所示: (1)挑选发生重叠的点云子集,这一步如果原始点云数据量比较巨大,一般会对原始点云进行下采样操作。 (2)匹配特征点。通常是距离最近的两个点,…

如何批量增加视频的音量(ffmpeg)

问题背景 由于之前爷爷的唱戏机充不进去电&#xff0c;过年时给爷爷买了个新的。但这个新买的机子&#xff0c;它的曲目&#xff08;视频&#xff09;在U盘里&#xff0c;声音普遍较低&#xff0c;我爷爷的耳朵不好&#xff0c;声音需要比正常的声音调大一些。 在Videolouder这…

【数据结构和算法】认识线性表中的链表,并实现单向链表

本文接着上文&#xff0c;上文我们认识了线性表的概念&#xff0c;并实现了静态、动态顺序表。接下来我们认识一个新概念链表。并实现单向链表的各种操作。顺序表还有不明白的看这一篇文章 (13条消息) 【数据结构和算法】实现线性表中的静态、动态顺序表_小王学代码的博客-CSDN…

leetcode--链表

链表1.链表的基本操作&#xff08;1&#xff09;反转链表(206)&#xff08;2&#xff09; 合并两个有序链表(21)&#xff08;3&#xff09;两两交换链表中的节点(24)2.其它链表技巧&#xff08;1&#xff09;相交链表(160)&#xff08;2&#xff09;回文链表(234)3.练习&#x…

力扣 2293. 极大极小游戏

题目 给你一个下标从 0 开始的整数数组 nums &#xff0c;其长度是 2 的幂。 对 nums 执行下述算法&#xff1a; 设 n 等于 nums 的长度&#xff0c;如果 n 1 &#xff0c;终止 算法过程。否则&#xff0c;创建 一个新的整数数组 newNums &#xff0c;新数组长度为 n / 2 &…

手把手带初学者快速入门 JAVA Web SSM 框架

博主也是刚开始学习SSM&#xff0c;为了帮大家节省时间&#xff0c;写下SSM快速入门博客 有什么不对的地方还请 私信 或者 评论区 指出 ​只是一个简单的整合项目&#xff0c;让初学者了解一下SSM的大致结构 项目先把框架写好&#xff0c;之后在填写内容 项目压缩包 完整的蓝奏…

浅谈phar反序列化漏洞

目录 基础知识 前言 Phar基础 Phar文件结构 受影响的函数 漏洞实验 实验一 实验二 过滤绕过 补充 基础知识 前言 PHP反序列化常见的是使用unserilize()进行反序列化&#xff0c;除此之外还有其它的反序列化方法&#xff0c;不需要用到unserilize()。就是用到了本文…

C 语言零基础入门教程(十一)

C 数组 C语言支持数组数据结构&#xff0c;它可以存储一个固定大小的相同类型元素的顺序集合。数组是用来存储一系列数据&#xff0c;但它往往被认为是一系列相同类型的变量。 数组的声明并不是声明一个个单独的变量&#xff0c;比如 runoob0、runoob1、…、runoob99&#xf…

【Linux】调试器 - gdb 的使用

目录 一、背景知识 二、debug 与 release 1、生成两种版本的可执行程序 2、debug 与 release 的区别 三、gdb 的使用 1、调试指令与指令集 2、源代码显示、运行与退出调试 3、断点操作 4、逐语句与逐过程 5、调试过程中的数据监视 6、调试过程中快速定位问题 一、背…