重点: 1.二者函数签名相同,调用方式是一致的
2. 怎么简单进行选择: 无脑选择useEffect,除非运行效果和你预期的不一致再试试useLayoutEffect
区别详解:
useEffect是异步执行,而且是在渲染被绘制到屏幕之后执行。
流程如下:
你以某种方式触发了rerender(改变state,或者父组件发生rerender)
React渲染你的组件(调用组件函数)
屏幕在视觉上更新(真实dom操作)
然后useEffect运行
useLayoutEffect是同步执行,时机在渲染之后但在屏幕更新之前。
流程如下:
你以某种方式触发了rerender(改变state,或者父组件发生rerender)
React渲染你的组件(调用组件函数)
useLayoutEffect运行,React等待它完成
屏幕在视觉上更新(真实dom操作)
代码实战:
const BlinkyRender = () => { const [value, setValue] = useState(0); useLayoutEffect(() => { if (value === 0) { setValue(10 + Math.random() * 200); } }, [value]); console.log('render', value); return ( <div onClick={() => setValue(0)}> value: {value} </div> ); };
当点击div时,状态立即改变(value重置为0),这将重新Render组件,然后运行Effect——将值设置为某个随机数,并再次重新Render。
也就是是两次Rerender会快速连续发生。分别换用useLayoutEffect和useEffect观察有什么不同。
你会发现useLayoutEffect的版本会在组件render两次的情况下仅在视觉上更新一次。而useEffect版本在视觉上也会呈现两次,所以会看到闪烁,从0闪烁变成对应的随机数。
所以到底什么时候使用useLayoutEffect呢?
如果你的组件在状态更新时闪烁,比如它首先以部分就绪状态呈现,然后立即以最终状态重新呈现——这是一个很好的线索,是时候换useLayoutEffect了。
当您的更新是两步(或多步)过程时,就会出现这种情况。你想在重新绘制屏幕之前一起批处理多个更新吗,试试useLayoutEffect。
在大多数情况下,你的effect函数会在对应的依赖项如state或props改变时执行,而对应的回调逻辑往往不会立即影响或根本不影响页面视觉。
比如发一个ajax请求
或者你设置一个了事件处理器
大多数时候,使用useEffect是正确的。如果您的代码导致闪烁,切换到useLayoutEffect,看看是否有帮助。
因为useLayoutEffect是同步的,也就是阻塞的,在你的effect运行完之前,视觉不会更新。如果你的effect中有计算密集型代码,它可能会导致性能体验问题,比如卡顿。大多数effect在运行时并不需要"stop the world",普通的 useEffect几乎可以满足我们所有的需求。