• useEffect使用指南


    React项目中如果使用函数式组件进行开发时,如果想在不使用class组件的情况下使用state和其他React特性,Hook将是你的不二选择。

    而Effect Hook又是一种比较常见的Hook,可以在函数式组件中执行副作用操作。刚开始可以理解为created、update生命周期。

    一、为effect添加依赖

        const [count, setCount] = useState(0)
    
        useEffect(() => {
            const fn = setTimeout(() => {
                console.log(count)
                setCount(count+1)。
            }, 1000)
        })
        // 0
        // 1
        // 2
    
        useEffect(() => {
            const fn = setTimeout(() => {
                console.log(count)
                setCount(count+1)
            }, 1000)
        },[])
        // 0

    effect的执行机制,是比较两次依赖项是否相同,不同则执行相关effect。

    如果不替effect添加依赖,则是比较两次effect。而我们知道在函数式组件中,每次渲染的state、effect都是不同的。只要组件内部状态发生变化就会执行effect。

    而将依赖项设置为一个固定值,则effect只会初始化时执行一次。

    二、effect内部状态自调用

    上面两种情况是比较简单的,在复杂的业务逻辑中,我们往往需要依据某个状态的变化然后再来执行副作用操作,并且还需要为effect设置清除函数。我们看看下面这段代码:

        useEffect(() => {
            const fn = setTimeout(() => {
                console.log(count)
                setCount(count+1)
            }, 1000)
            return () => clearTimeout(fn)
        },[count])
        // 0
        // 1
        // 2
    

    我们在effect中添加了清除函数,并且需要将count作为依赖在count变化时执行内部代码。这应该是大家使用Hook Effect比较常见的用法。

    但是就这个例子而言,这种设置依赖的写法是有逻辑漏洞的。在effect内部只需要将count做递增,而此时React是知道count的值,所以effect并不要使用count,可以使用setState的函数形式代替传参。

        useEffect(() => {
            const fn = setTimeout(() => {
                console.log(count)
                setCount(c => c+1)
            }, 1000)
            return () => clearTimeout(fn)
        })
        // 0
        // 1
        // 2
    

    setCount(c => c+1)就是在方法内部发送更新指令,告诉React去更新state的值,这样就将count从effect依赖中去掉,保持内部逻辑干净无污染。

    三、将函数放在effect内部

    有时一个effect内部函数代码量过多,我们可以将代码进行分割单独封装成函数,使整个逻辑看起来清晰明了。可能我们为了进一步追求代码规范,需要将函数抽离放在effect外部。

        const countPlayer = () => {
            return setTimeout(() => {
                setCount(count+10)
            },1000)
        }
    
        useEffect(() => {
           const fn = countPlayer()
           return () => clearTimeout(fn)
        },[])
        console.log(count)
        // 0
        // 10
    

    比如我们要在初始化时通过接口获取数据进行setState赋值然后渲染UI,并且获取数据操作只需要执行一次。上面的代码显示count为0时执行了effect副作用,通过countPlayer函数进行组件state初始化操作。第二次由于依赖没有变更就跳过了直接往后执行。

    逻辑上看起来没问题,但是如果当代码量过大并且存在多个函数嵌套依赖的情况,就很难保证准确更新相关effect依赖。并且如果项目安装了eslint-plugin-react-hooks,在项目打包运行时就会出现警告。

     这种情况,我们将函数移动到effect内部就能很好地规避这个问题。

    四、将函数放在effect外部

    如果一个函数在多个effect中被复用,这时我们就必须将函数放在effect外部了。至于逻辑漏洞和代码eslint告警的问题,一般有两种方法解决:

    • 将函数转化成纯函数,移动到组件外部;
    • 使用useCallback Hook进行包装;

    如果一个函数没有使用组件内部任何state、props就可以转化成纯函数,在不同的effect中任意调用。

    如果函数内部需要对state等进行setState操作,可以使用useCallback将整个函数包装成一个依赖state的可变值,然后作为effect的依赖使用。

    可能有的小伙伴会问,为啥不直接将countPlayer函数作为依赖呢?下面我们看看这样设置后的运行情况。

        const countPlayer = () => {
            return setTimeout(() => {
                setCount(count+10)
            },1000)
        }
    
        useEffect(() => {
           const fn = countPlayer()
           return () => clearTimeout(fn)
        },[countPlayer])
        console.log(count)
        // 0
        // 10
        // 20
        // ...

    会出现无限循环自调用的bug。之前我们提过,在函数式组件内部,每次获取的函数体、state、effect都不一样,所以会导致effect陷入死循环。下面我们将函数用useCallback进行包装看看效果。

        const countPlayer = useCallback(() => {
            return setTimeout(() => {
                setCount(c => c+10)
            },1000)
        },[])
    
        useEffect(() => {
           const fn = countPlayer()
           return () => clearTimeout(fn)
        },[countPlayer])
        console.log(count)
        // 0
        // 10

    这样既满足了将函数体抽离出effect的目的;并且通过useCallback包装使函数体本身成为了一个拥有独立依赖的可变值,可以在不同的effect之间复用。

    至此,effect Hook一些常用的思路和使用技巧都讲解完毕!

  • 相关阅读:
    一、汇编基础知识
    PHP RabbitMQ消息队列演示代码
    PHP CentOS下安装PHP及部署ThinkPHP
    MySQL CentOS下安装MySQL
    ThinkPHP 对接支付宝支付接口
    ThinkPHP 获取当前页面完整的URL地址
    前端 Validform.js属性,用法及Ajax提交简介
    PHP 配置Xdebug调试工具
    ThinkPHP 原生分页功能改进,更好用更美观
    ThinkPHP 使用第三方phpmailer库发送邮件
  • 原文地址:https://www.cnblogs.com/lodadssd/p/13653331.html
Copyright © 2020-2023  润新知