IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> React+TS学习和使用(二) -> 正文阅读

[JavaScript知识库]React+TS学习和使用(二)

开启学习react+ts,本篇主要是react函数式组件必备Hook,结合TS一起了解。

一、Hooks

1、useState

App.tsx 中使用 useState 定义数据,以及修改数据的方法,并传递给 Comp.tsx 子组件:

const [num, setNum] = useState(0);

<Comp1 num={num} />
   

子组件接收:

import React from 'react'

const Comp1: React.FC = function (props) {
    return (
        <>
            <h3>{props.num}</h3>
            <button>累加</button>
        </>
    )
}
export default Comp1;
    

很明显,这么接收直接就报错。因为TS强制要求必须指定传参的字段及其类型,因此应当改为:

import React from 'react'

const Comp1: React.FC = function (props: {num: number}) {
    return (
        <>
            <h3>{props.num}</h3>
            <button>累加</button>
        </>
    )
}
export default Comp1;
    

而实际上这是TS中接口的简化写法,完整点应该写为:

import React from 'react'

interface IProps {
    num: number;
}

// 使用IProps接口定义字段类型
const Comp1: React.FC<IProps> = function (props) {
    return (
        <>
            <h3>{props.num}</h3>
            <button>累加</button>
        </>
    )
}

export default Comp1;
    

A. 事件直接父传子使用

目前 setNum 依然处于定义了但未使用的状态,因此ESlint又会一直给出提示,因此我们可以把这个累加的效果实现:

// 父组件:
<Comp1 num={num} setNum={setNum} />

// 子组件
interface IProps {
    num: number;
    // 设定setNum为any
    setNum: any
}

<button onClick={()=>props.setNum(props.num+1)}>累加</button>
    

注意:

这里虽然设置为any可以实现累加,但不建议这么操作。

因此,真正的做法:

import React from 'react'

interface IProps {
    num: number;
    setNum: (num:number)=>void;
}

// 使用IProps接口定义字段类型
const Comp1: React.FC<IProps> = function(props) {
    return (
        <>
            <h3>{props.num}</h3>
            <button onClick={()=>props.setNum(props.num+1)}>累加</button>
        </>
    )
}

export default Comp1;
    

B. 事件用子传父的做法

* 父组件
import React, {useState, useCallback} from 'react'
import Comp1 from 'components/Comp1'

const App: React.FC = () => {
    const [num, setNum] = useState(0)

	const toSetNum = (value: number) => setNum(value)

    return (
        <>
            <h2>你好世界</h2>
            <Comp1 num={num} toSetNum={()=>toSetNum} />
        </>
    )
}

export default App;
    

setNum(newValue):代表直接用新值替换初始值

setNum(preValue => newValue):代表用新值替换旧值

* 子组件
import React from 'react'

interface IProps {
    num: number;
    toSetNum: (num:number)=>void;
}

// 使用IProps接口定义字段类型
const Comp1: React.FC<IProps> = function(props) {
    return (
        <>
            <h3>{props.num}</h3>
            <button onClick={()=>props.toSetNum(props.num+1)}>累加</button>
        </>
    )
}

export default Comp1;
    

2、useEffect

React的Class Component中有 componentDidMountcomponentDidUpdatecomponentWillUnmount,但Function Component并没有。

A、componentDidMount

useEffect(()=>{
  console.log('componentDidMount')
}, [])	// 空数组表示不检测任何数据变化

    

B、comopnentDidUpdate

useEffect(()=>{
  console.log('comopnentDidUpdate')
}, [num])	// 如果数组中包含了所有页面存在的字段,也可以直接不写
   

如果监听路由的变化:

// 需要先安装路由,而且是react-router-dom@v6.x
useEffect(()=>{
  console.log('路由变化')
}, [location.pathname])

    

C、componentWillUnmount

useEffect(()=>{
  return ()=>{
    // callback中的return代表组件销毁时触发的事件
  }
}, [])
    

3、memo、useMemo与useCallback

在Function Component中,也不再区分mountupdate两个状态,这意味着函数组件的每一次调用都会执行内部的所有逻辑,就带来了非常大的性能损耗。useMemouseCallback都是解决上述性能问题的。

来看下面这段代码:

import React, { useState, useMemo, useCallback } from "react";

const Sub = () => {
  console.log("Sub被渲染了");	// 这行代码在父组件App2更新时,它也被迫一直更新
  return <h3>Sub组件</h3>;
};

export default function App2() {
  const [num, setNum] = useState<number>(0);

  const changeNum = () => setNum(num + 1)

  return (
    <div>
      <h2>num的值:{num}</h2>
      <button onClick={changeNum}>累加num</button>
      <Sub />
    </div>
  );
}

以上代码中可以测试出来,Sub组件的 console.log 在App2组件更新时,一直被迫触发,这就是典型的性能浪费。

A. memo

使用memo这个hook可以解决这一问题:

import React, { useState, memo } from "react";

// Sub组件需要被memo包裹
const Sub = memo(() => {
    console.log("Sub被渲染了");
    return <h3>Sub组件</h3>;
  });

export default function App2() {
  const [num, setNum] = useState<number>(0);
    
  const changeNum = () => setNum(num + 1)

  return (
    <div>
      <h2>num的值:{num}</h2>
      <button onClick={changeNum}>累加num</button>
      <Sub />
    </div>
  );
}
    

memo可以缓存组件,当组件的内容不受修改时,可以不更新该组件。

B. useCallback

但我们希望num的变化不造成Sub组件的更新:

import React, { useState, memo, useCallback } from "react";

interface ISubProps {
  changeNum: () => void;
}

// Sub组件需要被memo包裹
const Sub = memo((props: ISubProps) => {
  console.log("Sub被渲染了");
  return (
    <>
      <button onClick={props.changeNum}>累加num</button>
      <h3>Sub组件</h3>
    </>
  );
});

export default function App2() {
  const [num, setNum] = useState<number>(0);

  // 将这个changeNum函数使用useCallback包裹一次
  const changeNum = useCallback(()=>{
      setNum((num)=>num+1)
  }, [])

  return (
    <div>
      <h2>num的值:{num}</h2>
      <Sub changeNum={changeNum} />
    </div>
  );
}

C. useMemo

useMemo与useCallback大致相同,只是useMemo需要在回调函数中再返回一个函数,我们称之为高阶函数:

import React, { useState, memo, useMemo } from "react";

interface ISubProps {
  changeNum: () => void;
}

// Sub组件需要被memo包裹
const Sub = memo((props: ISubProps) => {
  console.log("Sub被渲染了");
  return (
    <>
      <button onClick={props.changeNum}>累加num</button>
      <h3>Sub组件</h3>
    </>
  );
});

export default function App2() {
  const [num, setNum] = useState<number>(0);

  // 将这个changeNum函数改为useMemo
  const changeNum = useMemo(() => {
    return () => setNum((num) => num + 1);
  }, []);

  return (
    <div>
      <h2>num的值:{num}</h2>
      <Sub changeNum={changeNum} />
    </div>
  );
}
  

4、自定义hook

React中的hook允许我们自定义,来尝试一个简单的:

自定义一个hook,将所有的小写字母改大写。

import React from 'react'

const word = "Hello World";

function useBigWord(w: string){
    return w.toUpperCase();
}

const App3 = () => {
    const bigWord = useBigWord(word)
    return (
        <div>
            <h3>小写:{word}</h3>
            <h3>大写:{bigWord}</h3>
        </div>
    )
}

export default App3
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-06-26 16:49:40  更:2022-06-26 16:49:47 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 17:03:57-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码