TypeScript在React项目中的使用实践总结

 更新时间:2021年04月22日 08:44:18   作者:陌上兮月  
这篇文章主要介绍了TypeScript在React项目中的使用总结,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

序言

本文会侧重于TypeScript(以下简称TS)在项目中与React的结合使用情况,而非TS的基本概念。关于TS的类型查看可以使用在线TS工具👉TypeScript游乐场

React元素相关

React元素相关的类型主要包括ReactNodeReactElementJSX.Element

  • ReactNode。表示任意类型的React节点,这是个联合类型,包含情况众多;
  • ReactElement/JSX。从使用表现上来看,可以认为这两者是一致的,属于ReactNode的子集,表示“原生的DOM组件”或“自定义组件的执行结果”。

使用示例如下:

const MyComp: React.FC<{ title: string; }> = ({title}) => <h2>{title}</h2>;

// ReactNode
const a: React.ReactNode =
  null ||
  undefined || <div>hello</div> || <MyComp title="world" /> ||
  "abc" ||
  123 ||
  true;

// ReactElement和JSX.Element
const b: React.ReactElement = <div>hello world</div> || <MyComp title="good" />;

const c: JSX.Element = <MyComp title="good" /> || <div>hello world</div>;

原生DOM相关

原生的 DOM 相关的类型,主要有以下这么几个:ElementHTMLElementHTMLxxxElment

简单来说: Element = HTMLElement + SVGElement

SVGElement一般开发比较少用到,而HTMLElement却非常常见,它的子类型包括HTMLDivElementHTMLInputElementHTMLSpanElement等等。

因此我们可以得知,其关系为:Element > HTMLElement > HTMLxxxElement,原则上是尽量写详细。

React合成事件相关

在 React 中,原生事件被处理成了React 事件,其内部是通过事件委托来优化内存,减少DOM事件绑定的。言归正传,React 事件的通用格式为[xxx]Event,常见的有MouseEventChangeEventTouchEvent,是一个泛型类型,泛型变量为触发该事件的 DOM 元素类型。

示例如下:

// input输入框输入文字
const handleInputChange = (evt: React.ChangeEvent<HTMLInputElement>) => {
  console.log(evt);
};

// button按钮点击
const handleButtonClick = (evt: React.MouseEvent<HTMLButtonElement>) => {
  console.log(evt);
};

// 移动端触摸div
const handleDivTouch = (evt: React.TouchEvent<HTMLDivElement>) => {
  console.log(evt);
};

与hooks的结合

在hooks中,并非全部钩子都与TS有强关联,比如useEffect就不依赖TS做类型定义,我们挑选比较常见的几个和TS强关联的钩子来看看。

useState

如果初始值能说明类型,就不用给 useState 指明泛型变量;

// ❌这样写是不必要的,因为初始值0已经能说明count类型
const [count, setCount] = useState<number>(0);

// ✅这样写好点
const [count, setCount] = useState(0);

如果初始值是 null 或 undefined,那就要通过泛型手动传入你期望的类型,并在访问属性的时候通过可选链来规避语法错误。

interface IUser {
  name: string;
  age: number;
}

const [user, setUser] = React.useState<IUser | null>(null);

console.log(user?.name);

useRef

这个 hook 比较特别,它通常有两种用途:

用来连接 DOM,以获取到 DOM 元素;

// 连接DOM,初始值赋值为null,不能是undefined,如要指明泛型变量需要具体到HTMLxxxElement
// 如果我们确定inputRef.current在调用时一定是有值的,可以使用非空断言,在null后添加!
const inputRef = useRef<HTMLInputElement>(null!);

const handleClick = () => {
  inputRef.current.focus(); // 当然不用非空断言,用inputEl.current?.focus()可选链也是可以的
}

return (
  <input ref={inputRef} />
  <button onClick={handleClick}>点击</button>
)

2.用来存储变量,由于是存储在函数式组件的外部,比起 useState,它不会存在异步更新的问题,也不会存在由capture-value特性引发的过时变量的问题,但是要注意赋值后由于ref引用没变,不会引起重渲染。

// 通过初始值来自动指明泛型变量类型
const sum = useRef(0);

// 通过.current直接赋值
sum.current = 3;
// 不存在异步更新问题
console.log(sum.current); // 3

useSelector

useSelector用于获取store中的状态,其第一个固定参数为函数,函数的入参即为store,而store的类型RootState需要在store中提前定义好,一种常见的定义如下:

在store.ts中:

const store = createStore(rootReducer);

export type RootState = ReturnType<typeof rootReducer>;

使用时:

const { var1, var2 } = useSelector((store: RootState) => store.xxx);

自定义 hook

如果我们需要仿照 useState 的形式,返回一个数组出去,则需要在返回值的末尾使用as const,标记这个返回值是个常量,否则返回的值将被推断成联合类型。

const useInfo = () => {
  const [age, setAge] = useState(0);

  return [age, setAge] as const; // 类型为一个元组,[number, React.Dispatch<React.SetStateAction<number>>]
};

redux相关

对于action的定义,我们可以使用官方暴露的AnyAction,放宽对于action内部键值对的限制,如下:

import { AnyAction } from "redux";

const DEF_STATE = {
  count: 0,
  type: 'integer'
};

// 使用redux的AnyAction放宽限制
function countReducer(state = DEF_STATE, action: AnyAction) {
  switch (action.type) {
    case "INCREASE_COUNT":
      return {
        ...state,
        count: state.count + 1,
      };
    case "DECREASE_COUNT":
      return {
        ...state,
        count: state.count - 1,
      };
    default:
      return state;
  }
}

export default countReducer;

规约

子组件的入参命名为[组件名]Props,如:

// 比如当前组件名为InfoCard
export interface InfoCardProps {
  name: string;
  age: number;
}

interface接口类型以大写开头;

为后端接口的出入参书写interface,同时使用利于编辑器提示的jsdoc风格做注释,如:

export interface GetUserInfoReqParams {
    /** 名字 */
    name: string;
    /** 年龄 */
    age: number;
    /** 性别 */
    gender: string;
}

其他

键名或键值不确定如何处理?

// 表示键名不确定,键值限制为number类型
export interface NotSureAboutKey {
  [key: string]: number;
}

// 当键名键值都不确定时,以下接口对任何对象都是适用的
export interface AllNotSure {
  [key: string]: any;
}

如何在接口中使用泛型变量?

所谓泛型,就是预定义类型。它的目的是:达到类型定义的局部灵活,提高复用性。我们通常会在接口中使用泛型,如:

// 通常,我们会为接口的泛型变量指定一个默认类型
interface IHuman<T = unknown> {
  name: string;
  age: number;
  gender: T;
}

// 其他地方使用时
const youngMan: IHuman<string> = {
    name: 'zhangsan',
    age: 18,
    gender: 'male'
}

到此这篇关于TypeScript在React项目中的使用总结的文章就介绍到这了,更多相关TypeScript在React使用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • React改变元素样式的操作代码

    React改变元素样式的操作代码

    这篇文章主要介绍了React技巧之改变元素样式,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-05-05
  • React-native桥接Android原生开发详解

    React-native桥接Android原生开发详解

    本篇文章主要介绍了React-native桥接Android原生开发详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-01-01
  • React Fiber与调和深入分析

    React Fiber与调和深入分析

    Fiber可以理解为一个执行单元,每次执行完一个执行单元,React Fiber就会检查还剩多少时间,如果没有时间则将控制权让出去,然后由浏览器执行渲染操作,这篇文章主要介绍了React Fiber架构原理剖析,需要的朋友可以参考下
    2022-11-11
  • react 定位组件源码解析

    react 定位组件源码解析

    这篇文章主要为大家介绍了react定位组件源码解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-03-03
  • react-draggable实现拖拽功能实例详解

    react-draggable实现拖拽功能实例详解

    这篇文章主要给大家介绍了关于react-draggable实现拖拽功能的相关资料,React-Draggable一个使元素可拖动的简单组件,文中通过代码示例介绍的非常详细,需要的朋友可以参考下
    2023-08-08
  • react-pdf 打造在线简历生成器的示例代码

    react-pdf 打造在线简历生成器的示例代码

    本文主要介绍了react-pdf 打造在线简历生成器的示例代码,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-02-02
  • 减少react组件不必要的重新渲染实现方法

    减少react组件不必要的重新渲染实现方法

    这篇文章主要为大家介绍了减少react组件不必要的重新渲染实现方法详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-01-01
  • React如何实现像Vue一样将css和js写在同一文件

    React如何实现像Vue一样将css和js写在同一文件

    这篇文章主要介绍了React如何实现像Vue一样将css和js写在同一文件问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-01-01
  • Reactjs + Nodejs + Mongodb 实现文件上传功能实例详解

    Reactjs + Nodejs + Mongodb 实现文件上传功能实例详解

    今天是使用 Reactjs + Nodejs + Mongodb 实现文件上传功能,前端我们使用 Reactjs + Axios 来搭建前端上传文件应用,后端我们使用 Node.js + Express + Multer + Mongodb 来搭建后端上传文件处理应用,本文通过实例代码给大家介绍的非常详细,需要的朋友参考下吧
    2022-06-06
  • React入门教程之Hello World以及环境搭建详解

    React入门教程之Hello World以及环境搭建详解

    Facebook 为了开发一套更好更适合自己的JavaScript MVC 框架,所以产生了react。后来反响很好,所以于2013年5月开源。下面这篇文章主要给大家介绍了关于React入门教程之Hello World以及环境搭建的相关资料,需要的朋友可以参考借鉴。
    2017-07-07

最新评论