前言:这周去简单了解了useEffect()和useLayoutEffect()的使用方式和区别,写下文章,记录学习的历程。
共同点
useEffect和useLayoutEffect的使用方式都是类似的,第一个参数接收一个函数,第二个参数为接收一个数组。如果只传一个空数组,逻辑处理函数里面的逻辑只会执行一次。如果第二个参数是数组,包含多个,useEffect不会执行多遍,而是会异步等待一轮setState更新全部完成、re-render之后才执行。
/*例子中useEffect和useLayoutEffect效果一样,笔者就只用useEffect作为代码贴出来*/
import React,{useState,useEffect, useLayoutEffect,} from "react";
const DrawCom = ()=>{
const [state,setState] = useState('初始数据')
const [count,setCount] = useState(0)
const [shuju,setShuju] = useState({age:5,a:{b:2}})
useEffect(() => {
setState("数据改变了");
setCount(2)
setCount(3)
console.log(state)
console.log(count)
},[count,state]);
useEffect(()=>{
console.log('shuju',shuju)
},[shuju])
function changeObj(){
setShuju(obj=>{
/**
* 例子1
* 这里的代码会发现控制台打印了最新的值但是视图却一直旧的值
*/
obj.age+=1
console.log('obj',obj)
return obj
/**
* 例子2
* 这里的代码可以做到视图同步更新
*/
let newObj = {...obj}
newObj.age+=1
//newObj.a.b+=1//这里需要注意,拓展运算符拷贝是“一深二浅”,第二层开始就是浅拷贝。所以这里修改是不会触发useEffect的
return newObj
})
}
return(
<>
<p>{state}</p>
<div>{shuju.age}</div>
<div>{shuju.a.b}</div>
<button onClick={()=>changeObj()}>Click</button>
</>
)
}
export default DrawCom
补充:上述会有两个小例子,例子1中改变obj指向的值是不会触发useEffect或useLayoutEffect,因为此时改变的是obj对象堆里面的值,需要改变栈里面的指向。所以笔者在例子2中使用了进行拓展运算符进行深拷贝一份,改变其指向地址,才会触发监听。
不同点
我们先来个小demo思考下
import React,{useState,useEffect, useLayoutEffect,} from "react";
const DrawCom = ()=>{
const [state,setState] = useState('初始数据')
useEffect(() => {
let i = 0;
while(i <= 1000000000) {
i++;
};
setState("数据改变了");
console.log('组件渲染了')
},[]);
// useLayoutEffect(()=>{
// let i = 0;
// while(i <= 1000000000) {
// i++;
// };
// setState("数据改变了");
// },[])
return(
<>
<p>{state}</p>
</>
)
}
export default DrawCom
第一次我们使用useEffect会发现,页面会先展示‘数据展示’,然后闪烁一下,变为‘数据改变了’。第二次我们将useEffect注释掉,换为useLayoutEffect,发现没有闪烁的行为,数据直接就是修改后的。这就是因为useEffect是异步执行的,而useLayoutEffect是同步执行的。
useEffect 的函数会在浏览器完成布局与绘制之后,在一个延迟事件中被调用。react渲染组件不必等待useEffect函数执行完毕,造成阻塞。
useLayoutEffect会在所有的 DOM 变更之后同步调用 effect。可以使用它来读取 DOM 布局并同步触发重渲染。在浏览器执行绘制之前,useLayoutEffect 内部的更新计划将被同步刷新。(有可能会阻塞dom渲染)useLayoutEffect 与 componentDidMount、componentDidUpdate 的调用阶段是一样的。
官网推荐我们推荐一开始先用 useEffect,只有当它出问题的时候再尝试使用 useLayoutEffect。百分之99的情况,使用useEffect就可以了,可能需要用到useLayoutEffect的情况就是,在使用useEffect的情况下,我们的屏幕会出现闪烁的情况(组件在很短的时间内渲染了两次)。
总结:useEffect和useLayoutEffect两个Hook还是比较容易使用,技术水平有限,能分享的暂时就这些。如有写得不妥之处,请各位大佬不吝赐教(* ̄︶ ̄)