写在前面

虽然拿React写了很多项目,自己搭过也用过很多三方脚手架,比如Antd Pro Arco Pro TDesign Starter再例如跨端的Taro但是因为工期还有自身原因,一直没有时间去深入一下React的各个Hooks正好这次借着参加更文活动的机会激励一下自己可以每天下班空闲之余可以多读一些深入了解一些吧,如果正在读文章的你也和我类似的情况欢迎一起交流学习

先跑个项目吧

快速便捷直接使用create-react-app

create-react-app react-day1
cd react-day1
yarn
yarn start

yarn start.png
哦!我的老伙计!看那,是熟悉的原子图标!!!让我们开始吧!

官方定义

use useEffect. The function passed to useEffect will run after the render is committed to the screen. Think of effects as an escape hatch from React’s purely functional world into the imperative world.

By default, effects run after every completed render, but you can choose to fire them only when certain values have changed.

翻译一下大概就是useEffect默认会在函数组件运行并完成渲染后被触发传进来的effect函数,当然我们也可以让他只在某些值发生改变的情况下触发effecthttps://reactjs.org/docs/hooks-reference.html#useeffect

useEffect

Hooks拥有两个参数。第一个参数为一个函数effect,在此函数内可以做一些渲染完成后的动作,同时也可以在内部return一个函数作为当前函数组件销毁时的清理函数类似,第二个为一个数组deps,当传递的数组为[]空时useEffect则只会在函数运行并渲染完后直接调用。但如果你往deps参数数组中传递了一个或多个的时候,useEffect将会在deps依赖中的元素发生改变时触发effect从而达到跟随props或者state更新而触发effect来达到不同目的的情况

严格模式下重复执行

使用create-react-app创建出来的应用默认会在入口处使用React.StrictMode来创建App,从而导致在React版本大于18的项目中出现useEffect调用两次的情况,此现象在生产模式下只会调用一次,如需关闭可以去掉React.StrictMode直接render

用于DOM完成渲染之后

在日常开发中我们经常需要对Table或者Profile等等组件的数据进行初始化,这时候使用useEffect会是一个不错的选择,例子如下

import React, { useEffect, useState } from 'react'

const fetchUserData = () => {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve({
                id: 1,
                userName: 'Gnod'
            })
        }, 1500)
    })
}

const ChildrenA = () => {
    const [profile, setProfile] = useState(null)

    useEffect(() => {
        fetchUserData().then(res => {
            setProfile(res)
        })
    }, [profile])
    return (
        <div>
            <div>
                UserName: {profile && profile.userName || '-'}
            </div>
        </div>
        
    )
}

export default ChildrenA

用于组件销毁时

此处类似于componentWillUnmount生命周期,可用于在组件销毁时进行一些操作,比如清除Interval或者发送埋点或者取消一些事件的订阅,例子如下

import React, { useEffect, useState } from 'react'

const ChildrenB = () => {
    const [count, setCount] = useState(0)

    useEffect(() => {
        const timer = setInterval(() => {
            setCount(old => old + 1)
        }, 100)
        return () => {
            clearInterval(timer)
        }
    }, [])
    return (
        <div>
            <div>
                Count: {count}
            </div>
        </div>
        
    )
}

export default ChildrenB

上述代码在useEffect被调用时创建了一个Interval

interval.png

并在useEffect提供的Destructor在销毁时清理掉了Interval弹出了提示

destory.png

用于State或Props更新时

由于State Props更新时触发effect的用法一致,所以就只拿state来作为例子,这里我们做了一个简单的计数器然后来监听计数器的每一次更新

import React, { useEffect, useState } from 'react'

const ChildrenC = () => {
    const [count, setCount] = useState(0)

    useEffect(() => {
        console.log('count updated', count)
    }, [count])

    return (
        <div>
            <div onClick={() => { setCount(count + 1) }}>
                Count: {count}
            </div>
        </div>
        
    )
}

export default ChildrenC

ChildrenC.png

观察控制台可以发现在每一次count发生改变的时候useEffect都帮我们调用了effect函数从而在console里面打印出了count updated: xxx

console.png

最后

这是写给自己的React巩固计划的第一篇,希望在下班空闲之余通过写作的方式可以更加深入了解React各个方面的知识

推荐阅读

【摸鱼加钟】- Vue3组件封装之Slots、Emit和Props穿透

Last modification:August 23rd, 2022 at 12:34 am
If you think my article is useful to you, please feel free to appreciate