五种有趣的 UseEffect 无限循环类型

2025-05-29 0 82

五种有趣的 UseEffect 无限循环类型

一般来说,无限循环被认为是不好的做法。但在一些边界 case 中,你没有任何选择,只能选择无限循环。了解 React无限循环模式是件好事。

五种有趣的 UseEffect 无限循环类型

无限循环没有无法停止时,最终浏览器会杀死你的代码正在运行的标签。所以不要使用没有任何断点的 “无限循环”。

useEffect

useEffect hook 允许我们在一个组件中表现出副作用。当 hooks 被引入 react 16 时,useEffect hooks 比其他 hooks 更有吸引力。因为它提供了 componentDidMount、componentDidUpdate 和 componentWillUnmount 生命周期方法的综合功能。

五种有趣的 UseEffect 无限循环类型

只有当依赖关系被改变时,useEffect hook 才会触发回调函数。而且它使用浅比较法来比较 hooks 的值。

你可以把 useEffect 看作是一块能量石,它是一块最强大的石头,如果你没有正确地处理它,这块石头会摧毁你。

五种有趣的 UseEffect 无限循环类型

缺失依赖

缺失依赖关系的 useEffect 通常被认为是一种不好的做法,所以总是尽量避免它。

思考一下下面的代码,它将一直调用 API。

  1. useEffect(()=>{
  2. fetch("/api/user")
  3. .then((res)=>res.json)
  4. .then((res)=>{
  5. setData(res);
  6. });
  7. });

会发生什么

如果 useEffect 只有在依赖关系发生变化时才触发回调,那为什么我们在这里会出现无限循环?

你需要考虑到 React 的另一个重要的法则,即 “当 state 或 props 发生变化时,组件将重新渲染”。

在这段代码中,我们使用 setData 在网络调用成功后设置状态值,它将触发组件的重新渲染。由于 useEffect 没有值可以比较,所以它将调用回调。

Fetch 将再次触发setData,setData将触发组件重新渲染,如此反复。

五种有趣的 UseEffect 无限循环类型

如何修复这个问题?

我们需要将依赖指定为空数组。

  1. useEffect(()=>{
  2. fetch("/api/user")
  3. .then((res)=>res.json)
  4. .then((res)=>{
  5. setData(res);
  6. });
  7. },[]);//<-dependencies

根据官方文档,省略依赖关系是不安全的

依赖性的作用

useEffect 使用浅层对象比较来确定数据是否被改变。因为奇怪的 JavaScript 条件判断系统 ??。

  1. varmark1=function(){
  2. return"100";
  3. };//唯一的对象引用
  4. varmark2=function(){
  5. return"100";
  6. };//唯一的对象引用
  7. mark1==mark2;//false
  8. mark1===mark2;//false

让我们看看以下代码

  1. importReact,{useCallback,useEffect,useState}from"react";
  2. exportdefaultfunctionApp(){
  3. const[count,setCount]=useState(0);
  4. constgetData=()=>{
  5. returnwindow.localStorage.getItem("token");
  6. };
  7. const[dep,setDep]=useState(getData());
  8. useEffect(()=>{
  9. setCount(count+1);
  10. },[getData]);
  11. return(
  12. <divclassName="App">
  13. <h1>HelloCodeSandbox</h1>
  14. <buttononClick={()=>setCount(count+1)}>{count}</button>
  15. <h2>Starteditingtoseesomemagichappen!</h2>
  16. </div>
  17. );
  18. }

函数 getData 作为依赖项被传入。

当你运行这段代码时,它将抛出 “超过最大更新” 的错误,这意味着代码有一个无限循环

五种有趣的 UseEffect 无限循环类型

发生了什么?

由于 useEffect 使用浅层比较法来比较数值。该函数的浅层比较将总是给出 false。

如何修复这个问题?

为了修复这个问题,我们需要使用另一个叫做 useCallback 的 hook。

useCallback 返回一个memoized 版本的回调,只在依赖关系改变时才会改变。

  1. constgetData=useCallback(()=>{
  2. returnwindow.localStorage.getItem("token");
  3. },[]);//<-dependencies

将数组作为依赖

你可能知道,二者的浅层比较总是假的,所以以数组形式传递依赖关系也会导致 “无限循环”。

让我们看看以下代码

  1. importReact,{useCallback,useEffect,useState}from"react";
  2. exportdefaultfunctionApp(){
  3. const[count,setCount]=useState(0);
  4. constdep=["a"];
  5. const[value,setValue]=useState(["b"]);
  6. useEffect(()=>{
  7. setValue(["c"]);
  8. },[dep]);
  9. return(
  10. <divclassName="App">
  11. <h1>HelloCodeSandbox</h1>
  12. <buttononClick={()=>setCount(count+1)}>{count}</button>
  13. <h2>Starteditingtoseesomemagichappen!</h2>
  14. </div>
  15. );
  16. }

这里,数组 dep 作为 useEffect 的依赖传入。

当你运行这段代码时,浏览器控制台会抛出这个错误。

发生了什么?

两个数组的浅层比较总是假的,所以 useEffect 总是会触发回调。

五种有趣的 UseEffect 无限循环类型

如果修复这个问题?

由于 useCallback 的返回是一个函数,我们不能使用。

那么,我们应该怎么办?

我们需要使用另一个名为 useRef 的 hook

五种有趣的 UseEffect 无限循环类型

useRef 返回一个可变的对象,.current 具有初始值。

将对象作为依赖

你可能会猜到两个对象的浅层比较总是假的,所以 useEffect 会一直触发回调。

让我们看看一下这段代码

  1. importReact,{useEffect,useState,useRef}from"react";
  2. exportdefaultfunctionHome(){
  3. const[value,setValue]=useState(["b"]);
  4. const{current:a}=useRef(["a"]);
  5. useEffect(()=>{
  6. setValue(["c"]);
  7. },[a]);
  8. }

data 是作为 useEffect 的依赖项传入的。

当你运行这段代码时,你的浏览器控制台将被抛出一个无限循环的错误。

这里发生了什么?

对象的浅层比较将永远是假的,所以它将触发 useEffect 的回调。

五种有趣的 UseEffect 无限循环类型

如果修复这个问题?

如果我们将依赖关系备忘化,我们就能打破无限循环。那么,如何做到这一点呢?

是的,我们将使用另一个名为 useMemo 的 hook。

五种有趣的 UseEffect 无限循环类型

useMemo 只有在依赖关系发生变化时才会重新计算记忆化的值。

  1. importReact,{useMemo,useEffect,useState}from"react";
  2. exportdefaultfunctionApp(){
  3. const[count,setCount]=useState(0);
  4. constdata=useMemo(
  5. ()=>({
  6. is_fetched:false,
  7. }),
  8. []
  9. );//<-dependencies
  10. useEffect(()=>{
  11. setCount(count+1);
  12. },[data]);
  13. return(
  14. <divclassName="App">
  15. <h1>HelloCodeSandbox</h1>
  16. <buttononClick={()=>setCount(count+1)}>{count}</button>
  17. <h2>Starteditingtoseesomemagichappen!</h2>
  18. </div>
  19. );
  20. }

错误的依赖

错误的依赖关系与 React 无关,甚至与 javascript 无关。当使用错误的依赖关系时,我们必须承担起责任。

让我们看看一下这段代码

  1. importReact,{useEffect,useState}from"react";
  2. constApp=()=>{
  3. const[text,setText]=useState("");
  4. useEffect(()=>{
  5. setText(text);
  6. },[text]);
  7. returnnull;
  8. };
  9. exportdefaultApp;

我希望没有必要解释这个问题模式和它的修复方法。如果你想知道解释和修复方法,请在评论中告诉我。

注意:有很多方法可以避免 React 组件内部的无限循环,我只提到了几种方法。

总是使用 eslint-plugin-react-hooks 或 create-react-app,它将帮助你在这些问题进入生产环境之前找到这些问题。

一家公司在一周内因无限循环而损失了 $ 7.2 w。

所以在使用 useEffect 的时候一定要特别小心。

原文:https://javascript.plainenglish.io/5-useeffect-infinite-loop-patterns-2dc9d45a253f

原文链接:https://mp.weixin.qq.com/s/FcXIOVy-3Nhm9GjmwhxZiQ

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

快网idc优惠网 建站教程 五种有趣的 UseEffect 无限循环类型 https://www.kuaiidc.com/89374.html

相关文章

发表评论
暂无评论