当前位置: 首页 > 科技观察

五种有趣的UseEffect无限循环

时间:2023-03-16 17:52:32 科技观察

一般来说,无限循环被认为是不好的做法。但在某些边界情况下,您别无选择,只能无限循环。很高兴了解React的无限循环模式。当无限循环没有失败停止时,浏览器最终会杀死您的代码运行的选项卡。所以不要使用没有任何断点的“无限循环”。useEffectuseEffecthook允许我们在组件中展示副作用。当react16中引入hooks时,useEffecthooks比其他hooks更具吸引力。因为它提供了componentDidMount、componentDidUpdate和componentWillUnmount生命周期方法的组合功能。useEffect钩子仅在依赖项更改时触发回调。并且它使用浅比较来比较钩子的值。你可以把useEffect想象成一块能量石,它是最强大的石头,如果你处理不当,它会摧毁你。useEffect缺少依赖项通常被认为是一种不好的做法,所以总是尽量避免它。考虑下面的代码,它一直调用API。useEffect(()=>{fetch("/api/user").then((res)=>res.json).then((res)=>{setData(res);});});如果useEffect仅在依赖项发生变化时触发回调,为什么我们这里会出现无限循环?您需要考虑React的另一个重要规则,即“当state或props发生变化时,组件将重新渲染”。在这段代码中,我们使用setData设置网络调用成功后的状态值,这将触发组件的重新渲染。由于useEffect没有可比较的值,它将调用回调。Fetch会再次触发setData,setData会触发组件重新渲染,以此类推。如何解决这个问题?我们需要将依赖项指定为一个空数组。useEffect(()=>{fetch("/api/user").then((res)=>res.json).then((res)=>{setData(res);});},[]);//<-dependencies根据官方文档,省略依赖项是不安全的。依赖关系的作用useEffect使用浅层对象比较来判断数据是否发生变化。因为奇怪的JavaScript条件系统??。varmark1=function(){return"100";};//唯一对象引用varmark2=function(){return"100";};//唯一对象引用mark1==mark2;//falsemark1===mark2;//false让我们看看下面的代码getItem("token");};const[dep,setDep]=useState(getData());useEffect(()=>{setCount(count+1);},[getData]);return(

HelloCodeSandbox

setCount(count+1)}>{count}

Startingeditingtosesomemagichappen!

);函数getData作为依赖传入。当你运行这段代码时,它会抛出一个“超出最大更新数”的错误,这意味着代码有一个无限循环。发生了什么?因为useEffect使用浅比较来比较值。这个函数的浅层比较总是会给出false。如何解决这个问题?要解决这个问题,我们需要使用另一个名为useCallback的钩子。useCallback返回回调的记忆版本,该版本仅在依赖项更改时更改。constgetData=useCallback(()=>{returnwindow.localStorage.getItem("token");},[]);//<-dependencies使用数组作为依赖你可能知道,两者之间的浅层比较总是错误的,因此,将依赖项作为数组传递也会导致“无限循环”。我们看下面的代码useState(["b"]);useEffect(()=>{setValue(["c"]);},[dep]);return(

HelloCodeSandbox

setCount(count+1)}>{count}

Startededitingtoseesomemagichappen!

);}在这里,数组dep作为依赖传入使用效果。当您运行此代码时,浏览器控制台将抛出此错误。发生了什么?两个数组的浅比较总是错误的,所以useEffect总是触发回调。如何解决这个问题?由于useCallback的返回是一个函数,我们不能使用它。那么,我们应该怎么做呢?我们需要使用另一个名为useRef的钩子,它返回一个可变对象,其中.current具有初始值。作为依赖项的对象正如您可能猜到的那样,两个对象的浅层比较总是错误的,因此useEffect将始终触发回调。我们看一下这段代码["a"]);useEffect(()=>{setValue(["c"]);},[a]);}数据作为useEffect的依赖传入。当您运行这段代码时,您的浏览器控制台将抛出一个无限循环错误。这里发生了什么?对象的浅比较永远是false,所以会触发useEffect的回调。如何解决这个问题?如果我们记住依赖关系,我们就可以打破无限循环。那么,如何做到这一点?是的,我们将使用另一个名为useMemo的钩子。useMemo仅在依赖项发生变化时重新计算memoized值。importReact,{useMemo,useEffect,useState}来自“反应”;exportdefaultfunctionApp(){const[count,setCount]=useState(0);constdata=useMemo(()=>({is_fetched:false,}),[]);//<-dependenciesuseEffect(()=>{setCount(count+1);},[data]);return(

HelloCodeSandbox

setCount(count+1)}>{count}

Starteditingtoseesomemagichappen!

);}错误的依赖错误的依赖与React甚至javascript无关。当使用错误的依赖项时,我们必须承担责任。我们来看看这段代码importReact,{useEffect,useState}from"react";constApp=()=>{const[text,setText]=useState("");useEffect(()=>{setText(text);},[文本]);returnnull;};exportdefaultApp;我希望没有必要解释这个问题模式以及如何解决它。如果您需要解释和修复,请在评论中告诉我。注意:有很多方法可以避免React组件内部的无限循环,我只提到了几种。始终使用eslint-plugin-react-hooks或create-react-app,它将帮助您在这些问题投入生产之前找到它们。由于无限循环,一家公司在一周内损失了7.2w。所以在使用useEffect时要非常小心。原文:https://javascript.plainenglish.io/5-useeffect-infinite-loop-patterns-2dc9d45a253f本文转载自微信公众号“前端铁蛋”,可通过以下二维码关注.转载本文请联系前端铁蛋公众号。