当前位置:   article > 正文

React + 项目(从基础到实战) -- 第三期

React + 项目(从基础到实战) -- 第三期

react内置hooks

useState

如何让页面动起来(实时更新)

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

  

const Demo:FC=()=>{

   let count=0; //普通js变量无法触发组件更新

  

  

   function add(){

    count++;

   
    console.log("count: ",count);

   }

    return <div>

        <button onClick={add}>add {count}</button>

    </div>

}

  
  

export default Demo;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

在这里插入图片描述

为什么采用

state的改变可以触发函数组件的更新
(如果js变量不在jsx中使用,别用useState)

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

  

const Demo:FC=()=>{

//    let count=0; //普通js变量无法触发组件更新

   const[count,setCount]=useState(0); //useState 可以触发组件更新

  

   function add(){

    // count++;

    setCount(count+1)

    console.log("count: ",count);

   }

    return <div>

        <button onClick={add}>add {count}</button>

    </div>

}

  
  

export default Demo;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

在这里插入图片描述

特点

  1. 不可变数据
    不修改原数据,而是传入新的值

  2. 异步更新|
    函数中无法直接获取最新的值
    在这里插入图片描述

  3. 可能被合并
    使用函数state可以解决这个问题

在这里插入图片描述

 setCount(()=>{

        return count+5

    })
  • 1
  • 2
  • 3
  • 4
  • 5

immer

是一个插件
解决state不可变数据的影响
安装 npm install -D immer

 import {FC,useState} from "react";

import {produce} from "immer";

  

const Demo : FC =()=>{

  

    const [list,setList]=useState(['x','y'])

    function add(){

        // setList(list.concat('z'));

        setList(

            produce(draft=>{

                draft.push('z')//直接在原数组上修改

            })

        )

  

    }

  

    return (

        <div>

        <h2>state 不可变数据</h2>

        <div>{JSON.stringify(list)}</div>

        <button onClick={add}>add  item</button>

  
  

        </div>

    )

}

  

export default  Demo;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54

useEffect

为什么

组件是一个函数,返回的是JSX片段,
组件初次渲染完成,即函数执行完成,
一般情况下函数执行完成就结束了
但是在state更新时,会触发组件更新,函数组件再次执行

为了解决以上问题,使用useEffect

import {FC,useEffect,useState} from "react"

const Demo:FC=()=>{

    useEffect(()=>{

        console.log("组件初次渲染完成");

  

        return ()=>{

            console.log("组件销毁时执行");

        }

    },[])//无依赖项,只执行一次

  

    const[count,setCount]=useState(0); //useState 可以触发组件更新

  

   function add(){

    // count++;

    setCount(()=>{

        return count+5

    })

    console.log("count: ",count);

   }

    return <div>

        <button onClick={add}>add {count}</button>

    </div>

  

}

  
  

export default Demo;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52

注意

发现useEffect 执行两次

在react 18 中,useEffect 在开发环境中执行两次,在生产环境中执行一次
(模拟组件生命周期,以便尽早暴露问题)
开发环境 npm run build 生存环境

useRef

  1. 操作DOM
  2. 可传入普通js变量,但是更新不会触发rerender

与vue3 ref 不同

  

import { FC,useRef } from "react";

  

const Demo:FC = () => {

     // 定义一个ref

    const inputRef = useRef<HTMLInputElement>(null) //dom节点

    const nameRef=useRef("pink") //不是dom节点,是一个普通的js变量

    function selectInput(){

        const input = inputRef.current;

        if(input){

            input.select(); // 选中输入框中的内容(Dom节点操作API)

        }

    }

  

    function changeName(){

        nameRef.current="blue"//修改ref的值,不引起rerender(state修改会触发组件更新)

        console.log(nameRef.current);

    }

    return (

        <>

        <input ref={inputRef} defaultValue={"hello world"}/>

        <button onClick={selectInput}>选中 input</button>

  

        <p>{nameRef.current}</p>

        <button onClick={changeName}>修改名字</button>

  

        </>

    )

}

  
  

export default Demo;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62

在这里插入图片描述

useMemo

缓存数据
不用每次执行函数组件(比如说 state修改)都重新生成 , 实现性能优化

import {FC,useMemo,useState} from "react"

  

const Demo : FC =()=>{

    const[num1,setNum1]=useState(0)

    const[num2,setNum2]=useState(0)

    const[text,setText]=useState("hello") //更新导致组件rerender

  
  

    const sum =useMemo(()=>{

        console.log("计算两数之和");//缓存

        return num1+num2;

    },[num1,num2])

  

    return (

        <>

        <p>sum = {sum}</p>

        <button onClick={()=>{setNum1(num1+1)}}>num1 : {num1}</button>

        <button onClick={()=>{setNum2(num2+1)}}>num2 : {num2}</button>

        <button onClick={()=>{setText(text+"1")}}>text : {text}</button>

        </>

    )

}

  
  
  

export default Demo;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

在这里插入图片描述

useCallback

缓存函数

import {FC,useCallback,useState} from "react"

  
  

const Demo : FC =()=>{

    const [text,setText] = useState("hello")

    const fn1=()=>{

        console.log("fn1 text",text);

    }

  

    const fn2=useCallback(()=>{

        console.log("fn2 text",text);

    },[text])

  

    return(

        <>

        <button onClick={fn1}>fn1</button>

        <button onClick={fn2}>fn2</button>

        <div>

            <input value={text} onChange={e=>setText(e.target.value)}></input>

        </div>

        </>

    )

}

  
  
  

export default Demo;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50

自定义hooks

抽离公共部分,复用代码

同步案例

监听鼠标位置

  1. 自定义hook
import { useState,useEffect } from "react";

  

//获取鼠标位置

function useMouse(){

    const [x,setX]=useState(0);

    const [y,setY]=useState(0);

    const mouseMoveHandler=(e:MouseEvent)=>{

        setX(e.clientX);

        setY(e.clientY);

    }

  
  

    useEffect(()=>{

    //监听鼠标事件

        window.addEventListener('mousemove',mouseMoveHandler);

    //组件销毁时,一定要解绑DOM事件!!(可能会导致内存泄漏问题)

    return ()=>{

        window.removeEventListener('mousemove',mouseMoveHandler);

    }

    },[])

  
  

    return {x,y}

  

}

  
  

export default useMouse;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  1. app.tsx 中引入
//导入自定义hook


import useMouse from "./hooks/useMouse.ts";

function App() {


  const {x, y} = useMouse();

  return(

    <>

    <p>

      App Page

    </p>

    <div>x: {x}</div>

    <div>y: {y}</div>
    </>

  )

  

}

  

export default App
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

异步案例

模拟加载效果

import { useState,useEffect } from "react";

//异步获取消息

function getInfo():Promise<string>{

    return new Promise(resolve=>{

        setTimeout(()=>{

          resolve(Date.now().toString())  

        },1500)

    })

}

  
  

//自定义钩子

const useGetInfo=()=>{

    const[loading,setLoading]=useState(true)

    const[info,setInfo]=useState("")

  

    useEffect(()=>{

        getInfo().then(info=>{

            setLoading(false)

            setInfo(info)

        })

    },[])

    return {loading,info}

}

  
  

export default useGetInfo;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

第三方hooks

提高开发效率

ahooks

react-hooks

hooks使用规则

  1. useXxx命名
  2. 组件内 获 其他hook 中可以调用
  3. 保证每次调用顺序一致(不能处于 if/for 内部)

面试题(闭包陷阱)

无法获取最新值

import {FC,useState} from 'react'

  

const Demo:FC =()=>{

    const[count,setCount]=useState(0)

    function add(){

        setCount(count+1)

    }

  

    function alertFn(){

      setTimeout(()=>{

        alert(count);

      },3000)

    }

  

    return(

        <>

        <p>闭包陷阱</p>

  

        <div>

        <span>{count}</span>

        <button onClick={add}>add</button>

        <button onClick={alertFn}>alert</button>

  

        </div>

        </>

    )

}

  
  

export default Demo;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58

使用ref解决在这里插入图片描述

import {FC,useState,useRef, useEffect} from 'react'

  

const Demo:FC =()=>{

    const[count,setCount]=useState(0)

    const countRef = useRef(0)

  

    function add(){

        setCount(count+1)

    }

  

    useEffect(()=>{

        countRef.current=count

    },[count])

  

    function alertFn(){

      setTimeout(()=>{

        // alert(count); //count 值类型

        alert(countRef.current); // ref 引用类型

      },3000)

    }

  

    return(

        <>

        <p>闭包陷阱</p>

  

        <div>

        <span>{count}</span>

        <button onClick={add}>add</button>

        <button onClick={alertFn}>alert</button>

  

        </div>

        </>

    )

}

  
  

export default Demo;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72

在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/383434
推荐阅读
相关标签
  

闽ICP备14008679号