ReactHook - useEffect、useLayoutEffect

ReactHook - useEffect、useLayoutEffect
useEffect作用推迟代码执行渲染完成之后再执行常用于 数据读取完成移除 - 组件卸载的时候做一些清理的工作例如移除定时器、事件监听器等有关组件卸载触发时机当组件从 DOM 中移除时会触发useEffect里返回的函数useEffect里的内容不会执行执行也没有意义了。当组件出现在DOM中时会执行useEffect里的代码useEffect里返回的函数不执行。importReact,{useState,useEffect}fromreact;functionTimerComponent(){const[count,setCount]useState(0);useEffect((){consttimersetInterval((){setCount(prevCountprevCount1);},1000);// 返回的函数将在组件卸载时执行return(){clearInterval(timer);console.log(Timer cleared);};},[]);// 空依赖数组effect 只在挂载和卸载时运行returndivTimer:{count}/div;}exportdefaultTimerComponent;该行为是模拟了componentWillUnmount常用于清理操作例如取消网络请求、清除计时器或移除事件监听器。补充何时执行componentWillUnmount组件从页面移除当用户导航到另一个页面或条件渲染使得组件不再显示时componentWillUnmount 会被调用。在上面的例子中当 TimerComponent 被移除时计时器会被清除。父组件卸载如果父组件卸载了所有子组件也会卸载它们的 componentWillUnmount 也会被调用。第二个参数来模拟生命周期。对于缓存的对象来说因为每次函数都重新执行因此对象的引用会变所以useEffect第二个参数缓存的是引用的地址。useEffect存在一种bail out(保释) / (补救)机制当你尝试设置相同的状态仅仅让你把函数执行完但不会再触发effect。同理在class组件中的setState也是一样。setStatestate设置重复的值 —— 只会重复渲染一次 11. 推迟代码执行例如上面其实本来就是一种错误的写法只是React官方帮你兜了个底。正确的做法是2. 完成移除 定时器、监听functionHOC(){const[count,setCount]useState(0);useEffect((){console.log(创建)return(){console.log(销毁)}});return(button onClick{()setCount(count1)}按钮/button/)}exportdefaultHOC;当状态变化的时候重新渲染重新渲染导致useEffect执行前提是没有依赖项。在第一次刷新的时候不执行useEffect返回的函数只执行useEffect里的内容。后面状态变化导致重新渲染的时候会优先执行useEffect返回的函数然后再执行useEffect里的内容。例如页面初始化时第一次点击按钮时useEffect - clean-up阶段有两个删除组件重新渲染当前组件1. 第一个删除组件的时候执行注意useEffect里的回调如果有返回值的话必须是一个函数。会先执行这个return函数例如下面的代码。2. 第二个重新渲染的时候执行开发环境StrictMode下useEffect跑两遍在开发环境中React 可能会让组件经历类似下面的流程第一次挂载 mount - 执行 useEffect 立刻模拟卸载 unmount - 执行 useEffect 的 cleanup 清理函数 再次挂载 mount - 再执行 useEffect所以你会看到useEffect(() { console.log(effect run); return () { console.log(cleanup); }; }, []);开发模式下可能打印effect run cleanup effect run但这不是 bug也不是生产环境行为。这是 React 在开发环境下故意做的检查。注意错误的使用state会导致资源泄露例如1.某种异步操作开始——非常长2.组件已经被卸载了3.setState - 资源(内存泄露、socket泄露主要是内存泄露)泄露代码如下会报如下警告⚠️Warning: Can’t perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.in Unknown (at App.js:13)解决方法3. 第三种 第二个参数来模拟生命周期。useEffect选择执行当a变化才打印effect a当b变化才打印effect b类似于[a]这种形式 官方叫做 ”跳过“useEffect模拟生存周期函数useEffect(fn, [值]);如componentDidMountuseEffect() 的callback返回函数的case其实是根据当前操作来的是添加移除定时器还是添加移除dom执行效果是不一样的具体可以参考useEffect() 有始有终useLayoutEffect是 React 提供的一个 Hook你可以把它理解为**“在浏览器把画面绘制出来之前React 给你的最后一次修改 DOM 的机会”**。它的功能签名和useEffect几乎一模一样但核心区别在于执行时机。useEffect vs useLayoutEffect为了理解它我们需要看浏览器的渲染流程React 更新 DOM→useLayoutEffect 执行→浏览器绘制 (Paint)→useEffect 执行特性useEffect (常用)useLayoutEffect (特殊)执行时机浏览器绘制完成后异步执行浏览器绘制之前同步执行视觉体验如果修改了布局用户可能会看到闪烁先显示旧位置再跳到新位置用户看不到中间状态直接看到最终结果无闪烁性能影响不阻塞浏览器绘制性能较好会阻塞浏览器绘制用多了会导致页面卡顿比喻演出开始后你在后台改道具幕布拉开前你冲上去把道具摆好 什么时候必须用 useLayoutEffect只有当你需要读取 DOM 布局如宽高、位置并立即同步修改 DOM时才使用它。主要用于解决“视觉闪烁”问题。典型场景 1防止弹窗/气泡定位闪烁假设你要做一个 Tooltip气泡提示它需要显示在按钮的上方。如果用useEffect页面先渲染 Tooltip 在默认位置比如左上角 - 浏览器绘制 -useEffect计算按钮位置 - 修改 Tooltip 位置 - 用户看到 Tooltip“闪”了一下跳到了按钮上方。如果用useLayoutEffectReact 更新 DOM -useLayoutEffect立即计算位置并修改 - 浏览器绘制直接画出正确位置的 Tooltip - 用户完全感觉不到位置修正的过程。典型场景 2根据内容调整布局比如你需要根据一个容器的实际宽度来决定里面放几个卡片。你需要先测量容器宽度再决定渲染逻辑这个过程必须在绘制前完成。典型场景 3强制同步滚动比如进入聊天室你希望滚动条直接到底部不想让用户看到“先在顶部再跳到底部”的过程。⚠️ 什么时候不要用绝大多数情况下请优先使用useEffect。以下场景不要用useLayoutEffect数据请求 (API 调用)事件订阅/监听日志记录、埋点写入 LocalStorage任何不依赖 DOM 测量的操作因为在这些场景下使用useLayoutEffect只会徒增性能开销阻塞页面渲染带来卡顿风险。 总结口诀“涉及测量和布局修正怕闪就用useLayoutEffect其他所有副作用统统用useEffect。”useLayoutEffect是 React16.8.0版本引入的。

最新新闻

日新闻

周新闻

月新闻