React+hooks+TS练习

2023-05-16

一、初始化项目

  1. 通过create-react-app命令创建项目,–template表示使用typescript(node版本高于14才能使用npx)

     npx create-react-app jira --template typescript
    
  2. 配置绝对路径
    在tsconfig.json中配置baseUrl,表示项目中的绝对路径是从src目录下开始寻找。
    在这里插入图片描述

  3. 使用json-server来Mock数据
    首先安装json-server:yarn add json-server -D
    在根目录下创建_json_server_mock__文件夹,用来存放模拟的数据(名字可随意)
    在这里插入图片描述

    在package.json中配置scripts,新增json-server的命令:"json-server": "json-server __json_server_mock__/db.json --watch --port 3001"
    在这里插入图片描述
    由于json-server默认跑在3000的端口号上,和项目跑的端口号冲突,因此修改json-server的端口号为3001。
    此时执行 npm run json-server 就可以启动json-server,进行数据的模拟。

  4. 配置api根路径
    在根目录下创建 .env 和 .env.development文件, .env 是项目上线后使用的, .env .development是开发中使用的。在.env.development文件中添加:
    REACT_APP_API_URL = http://localhost:3001
    在项目中使用:
    const apiUrl = process.env.REACT_APP_API_URL

二、JSX实现小demo

通过本demo的实现,可对React的状态提升、组件结合、数据传递和两个最基本hook有了一个完整的使用过程。
在这里插入图片描述
接口格式
在这里插入图片描述
在这里插入图片描述

实现思路:可分成search_panel和list两个组件,在index中进行状态的保存,将状态通过props传递给search_panel和list两个组件使用。

// index.js
const apiUrl = process.env.REACT_APP_API_URL;

export const ProjetcList = () => {
 
    const [param, setParam] = useState({
        name: '',
        personalId: ''
    })

    // 存放底部列表数据
    const [list, setList] = useState([])

    // 存放下拉列表数据
    const [users, setUsers] = useState([])

    // input输入框或者下拉框内容改变,则请求数据
    useEffect(() => {
        fetch(`${apiUrl}/projects?${qs.stringify(cleanObj(param))}`).then(async response => {
            if(response.ok) {
                setList(await response.json())
            }
        })
    }, [param])

    // 请求users
    useEffect(() => {
        fetch(`${apiUrl}/users`).then(async response => {
            if(response.ok) {
                setUsers(await response.json())
            }
        })
    }, [])

    return (
        <div>
            <SearchPanel users={users} param={param} setParam={setParam}/>
            <List users={users} list={list}/>
        </div>
    )
}

注意:cleanObj方法用来处理param对象中值为空的情况,防止向服务端发送空参数。例如页面刚加载完,input为空,select也没有选中,此时param中的name和personId都是空的,在后端中就匹配不到这一项。

export const SearchPanel = ({users, param, setParam}) => {

    return (
        <form>
            <div>
                <input type="text" value={param.name} onChange={event => setParam({
                    ...param,
                    name: event.target.value,
                })} />

                <select value={param.personId} onChange={event => setParam({
                    ...param,
                    personId:event.target.value
                })}>
                    <option value="">负责人</option>
                        {users.map(user => <option value={user.id} key={user.id}>{user.name}</option>)}
                </select>
            </div>
        </form>
    )
}

注意:{ ...param, name: event.target.value }相当于Object.assign({}, params, name: event.target.value)

export const List = ({users, list}) => {
    // console.log(users, list);
    return(
        <table>
            <thead>
                <tr>
                    <th>名称</th>
                    <th>负责人</th>
                </tr>
            </thead>
            <tbody>
                
                {
                    list.map(project => <tr key={project.id}>
                        <td>{project.name}</td>
                        <td>{users.find(user => user.id === project.personId)?.name || '未知'}</td>
                    </tr>)
                }
            </tbody>
        </table>
    )
}

注意:{users.find(user => user.id === project.personId)?.name || '未知'}此处添加?是因为users初始化的时候还是空数组,会出现undefined.name得情况,此时控制台会报错。加上?就会将整句当成undefined,而不会报错,最终显示'未知'

接下来对demo进行优化处理:
初始化函数处理
在下拉框中,这个uers数组是不变的,只需要初始化的时候请求一下即可,因此useEffect第二个参数为空数组。

    // 请求users
    useEffect(() => {
        fetch(`${apiUrl}/users`).then(async response => {
            if(response.ok) {
                setUsers(await response.json())
            }
        })
    }, [])

但是如果页面中有很多需要进行初始化的函数,那么就会出现满屏都是useEffect(()=>{},[])的情况,因此在这里对初始化的函数进行简单操作:

export const useMount = (callback) => {
    useEffect(() => {
        callback();
    }, [])
}

调用的时候就是:

useMount(() => {
        fetch(`${apiUrl}/users`).then(async response => {
            if(response.ok) {
                setUsers(await response.json())
            }
        })
    })

咋一看和之前没多少变化,实则少了一个[]!!!

防抖处理
在useEffect中,只要param改变,就会触发请求函数,这就导致input输入框中每次键盘按下,就会发起一次get请求,造成很大的性能浪费。

// 简单的防抖函数
const debounce = (func, delay) => {
    let timer;
    return (...param) => {
        if(timer) {
            clearTimeout(timer)
        }
        timer = setTimeout(() => {
            func(...param)
        }, delay)
    }
}
// 使用自定义hook的防抖函数
export const useDebounce = (value, delay) => {
    const [ debouncedValue, setDebouncedValue ] = useState(value);

    useEffect(() => {

        // 当value值改变,就开启一个新的定时器
        const timer = setTimeout(() => { setDebouncedValue(value)}, delay)

        // 在useEffect函数中,return后面的回调函数是在上一次useEffect执行完后调用的
        return () => clearTimeout(timer)

    }, [value, delay])
    
    return debouncedValue;
}

这样一来,在输入间隔不超过delay毫秒的过程中,请求不会被触发,只有等到最后一个setTimeout执行完之后才会发送请求。在代码中使用:

    const debouncedParam = useDebounce(param, 1000);

    // input输入框或者下拉框内容改变,则请求数据
    useEffect(() => {
        fetch(`${apiUrl}/projects?${qs.stringify(cleanObj(debouncedParam))}`).then(async response => {
            if(response.ok) {
                setList(await response.json())
            }
        })
    }, [debouncedParam])

接下来将该demo改为ts的语法格式,将所有文件后缀改成.tsx或.ts,在代码中使用interface定义参数的类型

// SearchPanel 
export interface User {
    id: number;
    name: string;
}

interface SearchPanelProps {
    users: User[],
    param: {
        name: string,
        personId: string,
    };
    setParam: (param: SearchPanelProps['param']) => void;
}

export const SearchPanel = ({users, param, setParam}:SearchPanelProps) => {})

在index页面中,qs提示报错,这是因为当前下载的qs依赖中没有index.d.ts文件,该文件的作用就是对qs的js文件做了类型定义。命令行执行yarn add @types/qs -D,安装后此处的报错就没有了。

interface Project {
    id: number;
    name: string;
    personId: number;
    pin: boolean;
    organization: string;
}

interface ListProps {
    users: User[],
    list: Project []
}

export const List = ({users, list}: ListProps) => {

注意:在代码中可使用 // @ts-ignore将ts告警忽略掉

三、登录

进行登录部分功能开发,首先编写基本代码:

export const LoginScreen = () => {

    const handleSubmit = () => {

    }

    return <form onSubmit={handleSubmit}>
        <div>
            <label htmlFor="username">用户名</label>
            <input type="text" id={'username'} />
        </div>
        <div>
            <label htmlFor="password">密码</label>
            <input type="password" id={'password'} />
        </div>
        <button type="submit">登录</button>
    </form>
}

实现登录函数,点击登录后将username和password这两个参数传给服务端。

const handleSubmit = (event: FormEvent<HTMLFormElement>) => {
		// 阻止表单默认行为
        event.preventDefault();
        // 类型断言
        const username = (event.currentTarget.elements[0] as HTMLFormElement).value;
        const password = (event.currentTarget.elements[1] as HTMLFormElement).value;
        login({ username, password })
    }

实现调用登录api的函数

const apiURL = process.env.REACT_APP_API_URL;

const login = (params: { username: string; password: string; }) => {
        fetch(`${apiURL}/login`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(params)
        }).then(
            async (response) => {
                if(response.ok) {
                    
                }
            }
        )
    }

由于json-server无法调用自定义api,这里使用middleware来配置json-server:

  1. 在__json_server_mock__文件夹下新建middleware.js文件,改文件包含nodejs代码,因此必须符合CommonJS规范。

  2. 在middleware.js中编写以下代码:

    module.exports = (req, res, next) => {
        if(req.method === 'POST' && req.path === '/login') {
            // 测试账号
            if(req.body.username === 'jack' && req.body.password === '123456') {
                return res.status(200).json({
                // 返回一个token,供测试使用
                    user: {
                        token: '123'
                    }
                })
            } else {
                return res.status(400).json({message: '用户名或密码错误'})
            }
        }
        next()
    }
    
  3. 最后将编写好的middleware注入到json-server中。在package.json中,给json-server后新增:--middlewares ./__json_server_mock__/middleware.js命令
    在这里插入图片描述

  4. 重启服务,输入正确的账号密码就能收到token
    在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

React+hooks+TS练习 的相关文章

  • react项目按需加载报错 .libraryName is not a valid Plugin property

    babel presets react app plugins import libraryName antd style true 原配置如上会报错 libraryName is not a valid Plugin property g
  • 虚拟列表的实现思路(附带react代码)

    虚拟列表实现思路 代码链接 div class 滚动容器 div class 撑起列表正常高度 div div class 列表容器 div class 列表项 div div div 1 列表项 的高度确定 2 利用 滚动容器 的高度计算
  • React仿写网易云音乐项目

    文章目录 一 项目功能说明 二 最终效果 三 文件目录结构说明 四 项目技术栈 五 核心技术 1 配置项目别名 craco craco 2 使用reset css进行 css 重置 3 使用CSS Sprites 精灵图 4 使用 memo
  • 对useReducer的理解

    useReducer是React提供的一个高级Hook 它不像useEffect useState useRef等必须hook一样 没有它我们也可以正常完成需求的开发 但useReducer可以使我们的代码具有更好的可读性 可维护性 可预测
  • ant design pro v5 配置拦截器,header

    ant design pro v5 配置拦截器 header 1 资料文档 https umijs org zh CN plugins plugin request requestinterceptors 2 编写app tsx 我这里是自
  • 配置使用Eslint的时候 版本错误 "eslint": "5.6.0" a different version of eslint was detected higher up in the tr

    1 如果你也遇到下面的问题 你可以 按照命令行提示的那样 下面这四步完成的一般就可以了 但是不排除你在运行的时候忘记下载某些依赖 1 删除 package lock json 不是package json 你可以选择 yarn lock 或
  • React页面设计初体验

    1 定制路由 export default login path login name login component layouts BlankLayout routes path login component Login Index
  • react组件状态同步-状态提升

    假设定义组件TemperatureInputSon import React from react class TemperatureInputSon extends React Component constructor props su
  • Notion笔记搭建博客网站 - NotionNext

    NotionNext是什么 NotionNext是我在Github上开源的基于Next js框架开发的博客生成器 目的是帮助写作爱好者们通过Notion笔记快速搭建一个独立站 从而专注于写作 而不需要操心网站的维护 它将您的Notion笔记
  • 关于Vue.js和React.js,听听国外的开发者怎么说?

    VueJS 与 ReactJS 到底怎么样如何 听听别人怎么说 使用所有新的库和框架 很难跟上所有这些库和框架 也就是说 这就需要您决定哪些是值得花时间的 让我们看看人们说什么 和Vue JS一起工作是很愉快的 我发现学习曲线很浅 然而 这
  • React的超详细讲解

    React React的重点 webpack webpack 是一个现代 JavaScript 应用程序的静态模块打包器 module bundler 当 webpack 处理应用程序时 它会递归地构建一个依赖关系图 dependency
  • react和react jsx基础

    本文是个人学习笔记 例子都是来自React Native官网 之前不是做前端的 没有使用过react 要学习react native做混合开发 react 包括react jsx还是得补补 react和react jsx react是一个j
  • 【react】回调函数形式的ref

    回调函数有3个特点 是我定义的函数 我没有调用这个函数 在我没有调用的情况下这个函数自己执行了 ref绑定一个箭头函数作为回调函数 可以输出以下这段看下 ref绑定的箭头函数是会自己执行的 class Demo extends React
  • React、Vue2.x、Vue3.0的diff算法

    前言 本文章不讲解 vDom 实现 mount 挂载 以及 render 函数 只讨论三种 diff 算法 VNode 类型不考虑 component functional component Fragment Teleport 只考虑 E
  • React 定时刷新接口

    通过 useEffect 在页面加载时调用 getNodeDetailList 列表接口 useEffect gt getNodeDetailList change 然后通过 setInterval 来进行定时刷新 useEffect gt
  • 值得收藏的UmiJS 教程

    点击上方关注 前端技术江湖 一起学习 天天进步 前言 网上的umi教程是真的少 很多人都只写了一点点 很多水文 所以打算自己写一篇 自己搭建umi 并封装了一下常用的功能 并用到公司实际项目中 umi介绍 Umi 是什么 Umi 中文可发音
  • error Missing “key“ prop for element in array react/jsx-key

    react遇到一个奇怪的问题 error Missing key prop for element in array react jsx key 检查了jsx中使用map的 都定义了key div otherList map item an
  • React配置@src根路径

    第一种 直接修改node modules包中的webpack config js文件 找到node modules react scripts config webpack config js文件 修改其中alias中的配置 添加 src
  • 如何提高React组件的渲染效率的?在React中如何避免不必要的render?

    面试官 说说你是如何提高组件的渲染效率的 在React中如何避免不必要的render 一 是什么 react 基于虚拟 DOM 和高效 Diff 算法的完美配合 实现了对 DOM 最小粒度的更新 大多数情况下 React 对 DOM 的渲染
  • React安装依赖 node_modules中有下载依赖项但package.json文件中没有依赖

    React安装依赖 node modules中有下载依赖项但package json文件中没有依赖 直接在下载依赖项后 加 S 就可以解决 随机 id 生成器 uuid nanoid npm install nanoid S S save

随机推荐

  • 【轨迹规划】贝塞尔曲线理解及C++实现n次贝塞尔曲线

    一 贝塞尔曲线 贝塞尔曲线 xff08 Bezier Curve xff09 是一种基于多项式的曲线表示方法 xff0c 由法国工程师Pierre B zier在20世纪50年代提出 它是图形学中广泛应用的一种曲线类型 xff0c 用于在二
  • web开发之HTTP响应报文

    web开发之HTTP响应报文 1 HTTP响应报文分析2 HTTP 状态码介绍 1 HTTP响应报文分析 HTTP 响应报文效果图 响应报文说明 响应行 状态行 HTTP 1 1 200 OK span class token commen
  • git删除本地分支和删除远程分支

    git 查看分支 git branch 查看本地分支 xff08 号绿色高亮就是所在分支 xff09 git branch a 查看远程分支 删除分支 删除之前要先切换到别的分支上 例 xff1a 我现在在test分支上 xff0c 想删除
  • Vscode 连接远程仓库(新手必须知道的知识点)

    常见命令 1 新建码云项目仓库 2 填写仓库名称 将 使用Readme文件初始化这个仓库 选项的勾取消 3 在项目文件夹内 按住Shift 43 鼠标右键打开Windows PowShell xff08 1 xff09 输入git init
  • ROS架构(五)——ROS的通信机制

    ROS架构 xff08 五 xff09 ROS的通信机制 目录 总述一 通信机制一 话题通信机制二 通信机制二 服务通信机制三 通信机制三 参数管理机制四 话题与服务的区别 总述 ROS的核心 分布式通信机制 ROS是一个分布式框架 xff
  • VNC远程登录操作Ubuntu16.04

    VNC远程登录操作Ubuntu16 04 目录 总述一 设置Ubuntu16 04 xff0c 允许进行远程控制二 安装vncserver三 安装dconf editor 取消权限限制 四 远程连接Ubuntu 16 04 总述 VNC实现
  • 安装Melodic在sudo rosdep init时报错:ERROR: cannot download default sources list from:***

    报错如下 xff1a ERROR cannot download default sources list from https raw githubusercontent com ros rosdistro master rosdep s
  • 机器视觉(一)——ROS中的图像数据

    机器视觉 xff08 一 xff09 ROS中的图像数据 目录 总述一 二维图像数据二 三维点云数据 总述 无论是USB摄像头还是RGBD摄像头 xff0c 发布的图像数据格式多种多样 xff0c 在处理这些数据之前 就需要了解这些数据的格
  • ROS与机器学习(三)——手写数字识别

    ROS与机器学习 xff08 三 xff09 手写数字识别 目录 1 理论基础2 TensorFlow中的MNIST例程2 1 创建模型2 2 训练模型2 3 评估模型 3 基于ROS实现MNIST3 1 初始化ROS节点3 2 设置ROS
  • centos7升级 cmake

    一 删除旧版本cmake 升级到最新版本前应事先删除旧版本内核 cmake version yum remove y cmake 二 安装需要的模块 yum install y libxml2 libxml2 devel bzip2 bzi
  • SQLyog错误解决方案

    使用sqlyog连接 Mysql 出现的错误 使用sqlyog连接 Mysql 出现的错误 使用sqlyog连接 Mysql 出现的错误使用sqlyog连接 Mysql 出现的错误1251错误原因 xff1a 解决方案 xff1a 使用sq
  • ubuntu在更新软件时出现E: Release file for http://security.ubuntu.com/ubuntu/dists/bionic-security/InRelease

    问题 E Release file for http security ubuntu com ubuntu dists bionic security InRelease is not valid yet invalid for anoth
  • LeetCode之二分查找实战2之第一个错误的版本(278)、猜数字大小(374)

    二分查找2 1 第一个错误的版本 278 2 猜数字大小 xff08 374 xff09 1 第一个错误的版本 278 题目描述 xff1a 简单题 你是产品经理 xff0c 目前正在带领一个团队开发新的产品 不幸的是 xff0c 你的产品
  • python之逻辑回归项目实战——信用卡欺诈检测

    信用卡欺诈检测 1 项目介绍2 项目背景3 分析项目4 数据读取与分析4 1 加载数据4 2 查看数据的标签分布 5 数据预处理5 1 特征标准化5 2 使用下采样解决样本数据不均衡 6 训练数据即划分数据集7 模型建立7 1 sklear
  • C++ 全局变量的跨文件使用

    文章目录 前言一 extern的使用二 容易犯的错误 前言 在写C 43 43 工程文件的时候 xff0c 往往会用到一些所有类都使用的数据 xff0c 比如数据文件等 xff0c 一种写法是写成静态类 xff0c 调用数据时使用类名加属性
  • VS2019使用C++创建winform界面

    用C 43 43 实现winform界面 算是对上一篇文章的补充吧 xff0c 实际上不需要那么繁琐也可以做到 事先准备 打开VS xff0c 新建一个CLR项目 如果在选项中没有发现CLR项目 xff1a 1 找到Visual Studi
  • c++面试题(亲测常问)

    注意 xff1a 此题为我自己面试被问到的 xff0c 及一些摘抄的 xff0c 如有侵权请联系我马上删除 xff01 1 2 32位指针地址所占字节数 为四 举例说明 xff1a char p char test 10 p 61 test
  • torchvision与torch的对应关系及下载链接

    https github com pytorch vision 另外 xff1a Ubuntu18下编译安装torchvision C 43 43 API的详细过程
  • Logisim计算机组成原理实验16位无符号比较器设计

    Logisim用4位无符号比较器构建16位无符号比较器 4位无符号比较器设计思路表达式构建 16位无符号比较器构建思路构建 4位无符号比较器设计 思路 不同位之间进行比较 xff0c 高位优先 真值表太麻烦 xff0c 可以利用表达式进行构
  • React+hooks+TS练习

    一 初始化项目 通过create react app命令创建项目 xff0c template表示使用typescript xff08 node版本高于14才能使用npx xff09 npx create span class token