文章目录

一、项目起航:项目初始化与配置二、React 与 Hook 应用:实现项目列表三、TS 应用:JS神助攻 - 强类型1.TS 的必要性2.代码更改

学习内容来源:React + React Hook + TS 最佳实践-慕课网

相对原教程,我在学习开始时(2023.03)采用的是当前最新版本:

项版本react & react-dom^18.2.0react-router & react-router-dom^6.11.2antd^4.24.8@commitlint/cli & @commitlint/config-conventional^17.4.4eslint-config-prettier^8.6.0husky^8.0.3lint-staged^13.1.2prettier2.8.4json-server0.17.2craco-less^2.0.0@craco/craco^7.1.0qs^6.11.0dayjs^1.11.7react-helmet^6.1.0@types/react-helmet^6.1.6react-query^6.1.0@welldone-software/why-did-you-render^7.0.1@emotion/react & @emotion/styled^11.10.6

具体配置、操作和内容会有差异,“坑”也会有所不同。。。

一、项目起航:项目初始化与配置

【实战】 一、项目起航:项目初始化与配置 —— React17+React Hook+TS4 最佳实践,仿 Jira 企业级项目(一)

二、React 与 Hook 应用:实现项目列表

【实战】 二、React 与 Hook 应用:实现项目列表 —— React17+React Hook+TS4 最佳实践,仿 Jira 企业级项目(二)

三、TS 应用:JS神助攻 - 强类型

1.TS 的必要性

作为正常人,我们在开发过程中难免会犯以下错误:

变量名写错参数少传、多传数组或对象变量层次弄错

相对 JS 在运行时(runtime)才会发现错误,TS 可以帮助我们在 静态代码 中及时定位错误,将 弱类型 的 JS 转为 强类型 的 TS 能够极大地降低我们编码过程中的误码率

2.代码更改

将项目中 src 下 js 文件后缀改为 ts,jsx 文件后缀改为 tsx,并对文件代码做如下修改:

有参数的组件使用 interface 声明参数类型公用类型的可以导出+引入不明确类型的显性赋予 unknow 类型 (严格版 any)不确定参数是否会传的使用 ?: 赋予类型用泛型来规范类型

更多 ts 知识学习可见:【笔记】TS入门

更改后的文件如下:

src\utils\index.ts

import { useEffect, useState } from "react";

export const isFalsy = (val: unknown) => (val === 0 ? false : !val);

// 在函数里,不可用直接赋值的方式改变传入的引用类型变量

export const cleanObject = (obj: object) => {

const res = { ...obj };

Object.keys(res).forEach((key) => {

//@ts-ignore

const val = res[key];

if (isFalsy(val)) {

//@ts-ignore

delete res[key];

}

});

return res;

};

export const useMount = (cbk: () => void) => useEffect(() => cbk(), []);

/**

* @param { 值 } val

* @param { 延时:默认 1000 } delay

* @returns 在某段时间内多次变动后最终拿到的值(delay 延迟的是存储在队列中的上一次变化)

*/

export const useDebounce = (val: V, delay: number = 1000) => {

// V 泛型,表示传入与返回类型相同

const [tempVal, setTempVal] = useState(val);

useEffect(() => {

// 每次在 val 变化后,设置一个定时器

const timeout = setTimeout(() => setTempVal(val), delay);

// 每次在上一个 useEffect 处理完以后再运行(useEffect 的天然功能即是在运行结束的 return 函数中清除上一个(同一) useEffect)

return () => clearTimeout(timeout);

}, [val, delay]);

return tempVal;

};

src\screens\ProjectList\index.jsx

import { SearchPanel } from "./components/SearchPanel";

import { List } from "./components/List";

import { useEffect, useState } from "react";

import { cleanObject, useDebounce, useMount } from "utils";

import * as qs from "qs";

const apiUrl = process.env.REACT_APP_API_URL;

export const ProjectListScreen = () => {

const [users, setUsers] = useState([]);

const [param, setParam] = useState({

name: "",

personId: "",

});

// 对 param 进行防抖处理

const lastParam = useDebounce(param);

const [list, setList] = useState([]);

useEffect(() => {

fetch(

// name=${param.name}&personId=${param.personId}

`${apiUrl}/projects?${qs.stringify(cleanObject(lastParam))}`

).then(async (res) => {

if (res.ok) {

setList(await res.json());

}

});

}, [lastParam]);

useMount(() => {

fetch(`${apiUrl}/users`).then(async (res) => {

if (res.ok) {

setUsers(await res.json());

}

});

});

return (

);

};

src\screens\ProjectList\components\List.jsx

import { User } from "./SearchPanel";

interface Project {

id: string;

name: string;

personId: string;

star: boolean;

organization: string;

}

interface ListProps {

users: User[];

list: Project[];

}

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

return (

{list.map((project) => (

{/* undefined.name */}

))}

名称负责人
{project.name}

{users.find((user) => user.id === project.personId)?.name ||

"未知"}

);

};

src\screens\ProjectList\components\SearchPanel.jsx

export interface User {

id: string;

name: string;

email: string;

title: string;

organization: string;

}

interface SearchPanelProps {

users: User[];

param: {

name: string;

personId: string;

};

setParam: (param: SearchPanelProps["param"]) => void;

}

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

return (

{/* setParam(Object.assign({}, param, { name: evt.target.value })) */}

type="text"

value={param.name}

onChange={(evt) =>

setParam({

...param,

name: evt.target.value,

})

}

/>

value={param.personId}

onChange={(evt) =>

setParam({

...param,

personId: evt.target.value,

})

}

>

{users.map((user) => (

{user.name}

))}

);

};

src\App.tsx

import "./App.css";

import { ProjectListScreen } from "screens/ProjectList";

function App() {

return (

);

}

export default App;

拓展学习:

【笔记】TS 泛型【实战】用 Custom Hook + TS泛型实现 useArray

部分引用笔记还在草稿阶段,敬请期待。。。

文章来源

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: