React hooks 使用注意点详解

React hooks 使用注意点详解

部分参考资料:https://blog.csdn.net/lunahaijiao/article/details/125454338

useEffect

  • count发生变化时执行副作用操作,可以将count作为依赖项传入数组中
  • 每次count改变都会执行image.png
  • 第一次渲染之后和每次更新之后都会执行,也可以是只有某些值发生变化之后执行,重点在于是每轮渲染结束后延迟调用( 异步执行 ),这是 useEffect 的好处,保证执行 effect 的时候,DOM 都已经更新完毕不会阻碍 DOM 渲染造成视觉阻塞。

副作用函数

useEffect用于处理组件的副作用。

  • 第一个参数是一个回调函数,在里面进行业务逻辑代码的书写(副作用操作)
  • 通常在副作用中进行ajax请求,事件的绑定与解绑,设置定时器与清除等等。
  • 第二个参数是依赖项数组,指定副作用函数的触发条件。
  • 如果不设置第二个参数,那么当该组件挂载和组件每渲染一次,副作用就会执行一次
  • 如果数组中的依赖设置为空,那么只会在组件挂载和卸载时执行一次副作用。在 useEffect 的回调函数中,可以执行组件挂载时的操作,并在return返回的清理函数中执行组件卸载前的操作(例如:清除定时器,取消订阅)。
  • 如果数组中存在依赖项,当组件挂载时和依赖项数组中的依赖发生变化,那么该副作用就会重新执行 ,在 useEffect 的回调函数中,return返回的清理函数在下一次 useEffect 执行前执行。

useLayoutEffect和 useEffect 的区别

  • useLayoutEffect在组件渲染之前执行,dom还没有更新的时候

useLayoutEffect 的使用方法和 useEffect 相同,区别是他们的执行时机。
如上面所说,effect 的内容是会在渲染 DOM 之后执行,然而并非所有的操作都能被放在 effect 都延迟执行的,例如,在浏览器执行下一次绘制前,需要操作 DOM 改变页面样式,如果放在 useEffect 中执行,会出现闪屏问题。而 useLayoutEffect 是在浏览器执行绘制之前被同步执行,放在 useLayoutEffect 中就会避免这个问题。
这篇文章中可以清楚的看到上述例子的具体实现:useEffect 和 useLayoutEffect 的区别

  1. useLayoutEffect 也可以返回一个清理函数
  2. useLayoutEffect在浏览器重新绘制屏幕之前触发image.png
  • image.png

useMemo

  • 只要父组件的状态更新,无论有没有对子组件进行操作,子组件都会进行更新
  • useMemo与memo的理念上差不多,都是判断是否满足当前的限定条件来决定是否执行callback函数,而useMemo的第二个参数是一个数组,通过这个数组来判定是否更新回调函数
  • 其他State的更新引起了一个本来不需要更新的函数再次执行,

useMemo的好处:

  • 可以减少不必要的循环和不必要的渲染
  • 可以减少子组件的渲染次数
  • 通过特地的依赖进行更新,可以避免很多不必要的开销,但要注意,有时候在配合 useState拿不到最新的值,这种情况可以考虑使用 useRef解决
  • useMemo的值不一定是最新的值
  • 如果依赖项没有变化函数不会执行
  • 回调函数运行与否取决于依赖数组image.png

useCallback

  • useCallback与useMemo依赖项都为空时,useMemo函数不会调用,useCallback会调用,只是引用没有变
const Validate: React.FC = () => {
  const [ab, setA] = useState(0)
  const a = useMemo(() => {
    console.log('meimo');
    return ab
  }, [])
  const bb = useCallback(() => {
    console.log('callback');
  }, [])

  return (
    <>
      <div>{ab}ab</div>
      <div>{a}a</div>
      <button onClick={() => setA(pre => ++pre)}>dsdffsd</button>
      <button onClick={bb}>clalbal</button>
    </>
  );
};

export default Validate;
  • useCallback与useMemo可以说是一模一样,唯一不同的是

  • useMemo返回的是函数运行的结果,而useCallback返回的是函数

  • 这个函数是父组件传递子组件的一个函数,防止做无关的刷新,其次,这个组件必须配合memo,否则不但不会提升性能,还有可能降低性能

  • 函数式React.memo组件的props,React.memo会比较props的变化,所以用useCallBack缓存函数的引用,但是这个函数依然会执行,只是缓存地址

  • 注意这里面的ts写法
    image.png
    image.png

useRef

  • ref.current不能作为其它 Hooks 的依赖项,useEffect()监听不到ref.current的变化
    • image.pngimage.png
    • image.png
    • image.png
  • 可以获取当前元素的所有属性,拿到dom元素
  • 缓存数据 useRef 可以拿到最新值
  • useRef 能拿到最新的值但是不适合渲染,如果渲染的话,不会变化,不会引起组件的从新渲染
  • 当你希望组件"记住"某些信息,但又不想让这些信息触发新的渲染时,你可以使用ref.
  • 获取 DOM 元素子组件实例对象
  • 存储渲染周期之间共享的数据;eg: 记录组件渲染次数
  • image.pngimage.pngimage.png
相关代码
import { Button } from "antd"
import { useEffect, useRef, useState } from "react"

const Parent = () => {
  useEffect(() => {
    console.log('父组件别渲染了')
  })
  return <>
    <div>paerent</div>
    <Child />
  </>
}
const Child = () => {
  const [a, setA] = useState(0)
  const reff = useRef(0)
  reff.current++
  useEffect(() => {
    console.log('reff.current改变了')
  }, [reff.current])
  return <>
    <div>{reff.current}</div>
    <Button onClick={() => reff.current++}>dfsdf</Button>
    <Button onClick={() => setA(pre => ++pre)}>usetate </Button>
  </>
}
export default Parent
const MockMemo: React.FC<any> = () => {
    const [count, setCount] = useState(4)
    const [show, setShow] = useState(true)
    const ref = useRef(6)
    const inputRef = useRef<any>(null)
    const add = useCallback(() => {
        // setCount(count => count + 1)
        // setCount(count => {
        //     console.log(count, 'dssdf');
        //     return count + 1
        // })
        // setCount(count + 1)
        ref.current = ref.current + 4
        console.log('useCallbackuseCallback', count, 'm', ref.current)

    }, [show])
    useEffect(() => {
        console.log('ref.currentref.变化了');
    }, [ref.current])
    return (
        <div>
            <div style={{ display: 'flex', justifyContent: 'flex-start' }}>
                <TestButton title="普通点击" onClick={() => { setCount(count + 1); }} />
                <TestButton title="useCallback点击" onClick={add} />
                <InputTest ref={inputRef}></InputTest>
            </div>
            <div>数字count {count}</div>
            <div>数字ref{ref.current}</div>
            <Button onClick={() => { setShow(!show); inputRef.current.focu() }}> 切换</Button>
        </div>
    )
}

const TestButton = React.memo((props: any) => {
    console.log(props.title, 'meomeo')
    return <Button type='primary' onClick={props.onClick} style={props.title === 'useCallback点击' ? {
        marginLeft: 20
    } : undefined}>{props.title}</Button>
})

const InputTest = React.forwardRef((props: any, ref: any) => {
    const refinput = useRef<any>(null)
    const focu = () => {
        refinput.current.focus()
    }
    useImperativeHandle(ref, () => {
        return {
            focu
        }
    })
    return <input type="text" ref={refinput} />
})
  • 21
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值