聊聊react useEffect 的使用心得

4,974 阅读3分钟

react useEffect 是hooks 中最难以理解的一个hooks, 在使用的时候时候需要理解他的执行, 更新到底发生了什么, 已经后续ui更新问题

先了解一下useEffect 函数的各个参数分别是什么, 为什么要写这个参数, 不写有什么问题?

   useEffect(() => {
       return () => {};
   }, []);
  • 上面是一个 useEffect 函数完整的写法, 来分析一下useEffect, 其中useEffect(() => {})中的 箭头函数 我个人理解为是useEffecteffect函数, 也就是副作用函数, effect 函数中的 return 后面的箭头函数 个人理解为 useEffect 函数的返还函数, 这个函数在 当前组件卸载的时候会执行, 最后 useEffect(() => { return () => {}; }, []); 中的最后一个参数 [], 是useEffect 函数的依赖项, 表示当前useEffect 依赖的数据发生改变后执行, 下面上图
function Test() {
    
    useEffect(() => {
        console.log('useEffect1')
    })

    useEffect(() => {
        console.log('useEffect2')
        return () => {
            console.log('useEffect2 卸载了')
        }
    })

    useEffect(() => {
        console.log('useEffect3')
        return () => {
            console.log('useEffect3 卸载了')
        }
    }, [])
    
    
    return (
        <div>Test</div>
    )
}

export default Test;

下面贴出 运行结果

WechatIMG14.png

下面增加一点东西, 来证明一下 上面的理解

import {useEffect} from "react";


function Test() {
    const [n ,setN] = useState(0);


    useEffect(() => {
            console.log('useEffect1')
    })

    useEffect(() => {
        console.log('useEffect2  n改变之后执行')
    },[n])

    useEffect(() => {
        console.log('useEffect3')
        return () => {
            console.log('useEffect3 组件卸载了')
        }
    }, [])


    return (
          <div>
            <div>n: {n}</div>
            <button onClick={() => setN(n+1)}>n+1</button>
          </div>
    )
}

export default Test;
function App() {

    const [isShow, setIsShow] = useState(true);
    return (
        <div>
            {isShow && <Test></Test>}
            <button onClick={()=> setIsShow(false)}>隐藏Test</button>
        </div>
    )
}

ReactDOM.render(<App />, document.getElementById(('root')))
来看看这段代码的执行结果

WechatIMG23.png

  • 在组件初始化, 三个effect 函数都会执行, 这个是没问题的, 下面来看看组件中的数据改变了是怎么执行的

WechatIMG12.png 如图所示, 我们点击 n+1按钮后, n 的值发生了改变, useEffect1useEffect2 执行了 ,而useEffect3并没有执行, 这是为什么呢?

WechatIMG13.png

通过上面的图片可以看出来, useEffect1useEffect2 的区别是, useEffect1 函数中的依赖项 并没有设置, 这个时候, useEffect1 函数在组件的初始化, 更新 都会执行, 而useEffect2 函数设置了依赖项n, 就是在n 变化和初始化的时候会执行, 在来看看useEffect3 函数为什么在页面初始化之后执行, 并且组件中有其他数据改变并不会执行, 这个我也是看别的博客了解来了的, 是因为useEffect3 函数的依赖项设置的是 [] 不依赖任何数据, 也就是页面初始化的时候会执行, 好了到这里我们弄清楚了 useEffect1useEffect2 执行了 ,而useEffect3并没有执行, 下面来看看 点击隐藏test 组件会发生什么

WechatIMG14.png 看到 useEffect3返还函数被执行了, 这里就可以当成class 组件的卸载阶段

最后贴上我自己总结的useEffect 函数的总结, 如有错误, 感谢指正

useEffect(()=> { return ()=> {}},[])

  • 参数 1 effect 函数 => 发送请求 修改数据 ...
  • 参数 2 effect 函数依赖参数 决定effect 的更新方式
  • return 返还函数 ==> 组件要卸载的时候做一些事情

执行机制

  • 挂载阶段 => 1 先执行useEffect 函数 , 并把effect 函数存入队列等待执行
  • 挂载完成 => 执行effect 函数队列

更新阶段

  • 执行新的的useEffect 函数 , 并肩effect 函数存入队列等待等待执行
  • 执行返还函数队列, 并观察返还函数书否有依赖参数, 有依赖参数, 追踪依赖参数是否改变, 改变执行, 没有改变不执行
  • 执行effect 函数队列, 观察effect 函数是否有依赖参数,有依赖参数, 追踪依赖参数是否改变, 改变执行, 没有改变不执行

卸载阶段

  • 1 执行返还函数队列