useEffect和useLayoutEffect有什么区别?

19 篇文章 2 订阅
10 篇文章 2 订阅

上一节我们介绍了useRef 保存引用值和useImperativeHandle 透传 Ref,这一节之后整个React hooks的学习就告一段落了。

useLayoutEffect 同步执行副作用

大部分情况下,使用 useEffect 就可以帮我们处理组件的副作用,但是如果想要同步调用一些副作用,比如对 DOM 的操作,就需要使用 useLayoutEffect,useLayoutEffect 中的副作用会在 DOM 更新之后同步执行。

function App() {
  const [width, setWidth] = useState(0);
  useLayoutEffect(() => {
    const title = document.querySelector("#title");
    const titleWidth = title.getBoundingClientRect().width;
    console.log("useLayoutEffect");
    if (width !== titleWidth) {
      setWidth(titleWidth);
    }
  });
  useEffect(() => {
    console.log("useEffect");
  });
  return (
    <div>
      <h1 id="title">hello</h1>
      <h2>{width}</h2>
    </div>
  );
}

在上面的例子中,useLayoutEffect 会在 render,DOM 更新之后同步触发函数,会优于 useEffect 异步触发函数。

useEffect和useLayoutEffect有什么区别?

简单来说就是调用时机不同,useLayoutEffect和原来componentDidMount&componentDidUpdate一致,在react完成DOM更新后马上同步调用的代码,会阻塞页面渲染。而useEffect是会在整个页面渲染完才会调用的代码。

官方建议优先使用useEffect

在实际使用时如果想避免页面抖动(在useEffect里修改DOM很有可能出现)的话,可以把需要操作DOM的代码放在useLayoutEffect里。关于使用useEffect导致页面抖动,参考git仓库git仓库示例。

不过useLayoutEffect在服务端渲染时会出现一个warning,要消除的话得用useEffect代替或者推迟渲染时机。

React Hooks 不足

尽管我们通过上面的例子看到 React Hooks 的强大之处,似乎类组件完全都可以使用 React Hooks 重写。但是当下 v16.8 的版本中,还无法实现 getSnapshotBeforeUpdate 和 componentDidCatch 这两个在类组件中的生命周期函数。官方也计划在不久的将来在 React Hooks 进行实现。

父组件

import Child from 'component/Child'
 
 const dataobj = {
     pdata1: 1,
     pdate2:2
}
 const [dataobj ,setDataobj ] = useState({});
 const pchildref = useRef();
 function parantHandler() {
    // 子组件调用的父组件方法
}
 function parentDivClick() {
    // 父组件调用子组件方法
    pchildref .current._childFn();
}
 return (
    <div>
        <Child
             ref={pchildref}
             params1={dataobj.pdata1}
             params2={dataobj.pdata2}
             handlerClick={parantHandler}>
        </Child>
        <div onClick={parentDivClick}></div>
    </div>
)

子组件

const Child = (props,ref) => {  
    // 接收父组件的传值
     const { params1,params2,handlerClick} = props;
     const childRef = useRef();
    // 暴露的子组件方法,给父组件调用
    useImperativeHandle(ref,() => {
         return {
            _childFn() {
                // something….
            }
        }
    })
    // handlerClick子组件调用父组件方法
     return <div
        ref={childRef} onClick={handlerClick}>
        </div>
}
// forwardRef 配合useRef 父组件调用子组件方法使用
export default forwardRef(Child);

关注我,一起学习更多的前端技术。

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端e站

如果有所帮助,欢迎来杯奶茶

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值