如何解决React useEffect钩子带来的无限循环问题
React的useEffect Hook
可以让用户处理应用程序的副作用
。例如:
从网络获取数据
:应用程序通常在第一次加载时获取并填充数据。这可以通过useEffect
函数实现操作UI
:应用程序应该响应按钮点击事件(例如,打开一个菜单)设置或结束计时器
:如果某个变量达到预定义值,则内置计时器应自行停止或启动
尽管useEffect Hook在React生态系统中很常见,但它需要时间来掌握。因此,许多新手开发人员在配置他们的useEffect函数时,会导致无限循环问题。在本文中,您将了解不同场景下带来的无限循环问题以及如何解决它们。
这是我们今天要学习的内容:
是什么导致无限循环以及如何解决它们:
- 在依赖项数组中不传递依赖项
- 使用函数作为依赖项
- 使用数组作为依赖项
- 使用对象作为依赖项
- 传递不正确的依赖项
什么导致的无限循环以及如何解决它们
在依赖项数组中不传递依赖项
如果您的useEffect函数不包含任何依赖项,则会出现一个无限循环。
例如,看看下面的代码:
function App() { const [count, setCount] = useState(0); //初始化值 useEffect(() => { setCount((count) => count + 1); }); //无依赖项 return ( <div className="App"> <p> value of count: {count} </p> </div> ); }
如果没有依赖关系,则默认在每个更新周期上触发useEffect。因此,这里的应用程序将在每次渲染时执行setCount函数。因此,这会导致一个无限循环:
是什么导致了这个问题?让我们一步一步来分析这个问题:
- 在第一次渲染时,React会检查
count
的值。在这里,由于count为0,程序执行useEffect函数 - 稍后,useEffect调用setCount方法并更新count的值
- 之后,React重新呈现UI以显示count的更新值
- 此外,由于
useEffect在每个呈现周期中运行
,它将重新调用setCount函数
- 由于上述步骤发生在每一个渲染,这导致你的应用程序崩溃
如何解决这个问题
为了缓解这个问题,我们必须使用依赖数组,告诉React只有在特定值更新时才调用useEffect。
下一步,像这样附加一个空白数组作为依赖项:
useEffect(() => { setCount((count) => count + 1); }, []); //empty array as second argument.
这告诉React在第一次装载时执行setCount
函数。
使用函数作为依赖项
如果你把一个方法传入你的useEffect
依赖数组,React会抛出一个错误,表明你有一个无限循环:
function App() { const [count, setCount] = useState(0); function logResult() { return 2 + 2; } useEffect(() => { setCount((count) => count + 1); }, [logResult]); // 函数作为依赖项 return ( <div className="App"> <p> value of count: {count} </p> </div> ); }
在这段代码中,我们将logResult
方法传递给useEffect
数组。理论上,React只需要在第一次渲染时增加count
的值。
是什么导致了这个问题?
- 要记住的一件事是,useEffect使用了一个叫做浅比较的概念。它这样做是为了验证依赖项是否已经更新
- 这里的问题是,在每次呈现期间,React都会重新定义logResult的引用
- 因此,这将在每个循环中重新触发useEffect函数
- 因此,React会调用setCount钩子,直到应用程序遇到更新深度错误。这会给程序带来错误和不稳定性
如何解决这个问题
一个解决方案是使用useCallback
钩子。这允许开发人员记住他们的函数,从而确保引用值保持不变。由于这个参考值是稳定的,React不应该无限地重新渲染UI:
const logResult = useCallback(() => { return 2 + 2; }, []); // logResult是缓存的 useEffect(()=> { setCount((count)=> count+1); },[logResult]); //没有无限循环错误,因为logResult引用保持不变。
结果:
使用数组作为依赖项
将数组变量传递给依赖项也会运行一个无限循环。考虑下面的代码示例:
const [count, setCount] = useState(0); //初始值为0。 const myArray = ["one", "two", "three"]; useEffect(() => { setCount((count) => count + 1); // 和前面一样,增加Count的值 }, [myArray]); // 将数组变量传递给依赖项
在这个块中,我们将myArray变量传入依赖参数。
是什么导致了这个问题?
既然myArray的值在整个程序中都没有改变,为什么我们的代码会多次触发useEffect ?
- 在这里,回想一下React使用浅比较来检查依赖项的引用是否发生了变化。
- 由于对myArray的引用在每次渲染时都在变化,useEffect将触发setCount回调
- 因此,由于myArray的引用值不稳定,React将在每个渲染周期中调用useEffect。最终,这会导致应用程序崩溃
如何解决这个问题
为了解决这个问题,我们可以使用useRefHook。这将返回一个可变对象,确保引用不会改变:
const [count, setCount] = useState(0); //提取“current”属性并给它赋值 const { current: myArray } = useRef(["one", "two", "three"]); useEffect(() => { setCount((count) => count + 1); }, [myArray]); //依赖值是稳定的,所以没有无限循环
将对象作为依赖项传递
在useEffect依赖数组中使用对象也会导致无限循环问题。
考虑下面的代码:
const [count, setCount] = useState(0); const person = { name: "Rue", age: 17 }; //创建一个对象 useEffect(() => { // 每次增加count的值 // person的值发生了变化 setCount((count) => count + 1); }, [person]); // 依赖项数组包含一个对象作为参数 return ( <div className="App"> <p> Value of {count} </p> </div> );
控制台的结果表明程序是无限循环的:
是什么导致了这个问题?
- 和之前一样,React使用浅比较来检查person的参考值是否发生了变化
- 因为person对象的引用值在每次渲染时都会改变,所以React会重新运行useEffect
- 因此,在每个更新周期中调用setCount。这意味着我们现在有了一个无限循环
如何解决这个问题
那么我们如何解决这个问题呢?
这就是usemmo
的用武之地。**当依赖关系发生变化时,这个钩子会计算一个记忆的值。**除此之外,因为我们记住了一个变量,这确保了状态的引用值在每次渲染期间不会改变:
// 使用usemo创建一个对象 const person = useMemo( () => ({ name: "Rue", age: 17 }), [] //没有依赖关系,所以值不会改变 ); useEffect(() => { setCount((count) => count + 1); }, [person]);
传递不正确的依赖项
如果将错误的变量传递给useEffect函数,React将抛出一个错误。
下面是一个简单的例子:
const [count, setCount] = useState(0); useEffect(() => { setCount((count) => count + 1); }, [count]); //注意,我们将count传递给了这个数组。 return ( <div className="App"> <button onClick={() => setCount((count) => count + 1)}>+</button> <p> Value of count{count} </p> </div> );
是什么导致了这个问题?
- 在上面的代码中,我们告诉在useEffect方法中更新count的值
- 此外,注意我们也将count Hook传递给了它的依赖数组
- 这意味着每次count值更新时,React都会调用useEffect
- 因此,useEffect钩子调用setCount,从而再次更新count
- 因此,React现在在一个无限循环中运行我们的函数
如何解决这个问题
要摆脱无限循环,只需像这样使用一个空的依赖数组:
const [count, setCount] = useState(0); // 只有在组件首次挂载时才更新'count'的值 useEffect(() => { setCount((count) => count + 1); }, []);
这将告诉React在第一次渲染时运行useEffect。
结尾
尽管React Hooks是一个简单的概念,但是在将它们整合到项目中时,仍然需要记住许多规则。这将确保您的应用程序保持稳定,优化,并在生产过程中不抛出错误。
此外,最近发布的Create React App CLI
也会在运行时检测和报告无限循环错误。这有助于开发人员在这些问题出现在生产服务器上之前发现并解决这些问题。
到此这篇关于如何解决React useEffect钩子带来的无限循环问题的文章就介绍到这了,更多相关React useEffect钩子无限循环内容请搜索猪先飞以前的文章或继续浏览下面的相关文章希望大家以后多多支持猪先飞!
原文出处:https://blog.csdn.net/ImagineCode/article/details/124627512
相关文章
关于React Native报Cannot initialize a parameter of type'NSArray<id<RCTBridgeModule>>错误(解决方案)
这篇文章主要介绍了关于React Native报Cannot initialize a parameter of type'NSArray<id<RCTBridgeModule>>错误,本文给大家分享解决方案,需要的朋友可以参考下...2021-05-12- 这篇文章主要介绍了React使用高德地图的实现示例(react-amap),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-04-18
React引入antd-mobile+postcss搭建移动端
本文给大家分享React引入antd-mobile+postcss搭建移动端的详细流程,文末给大家分享我的一些经验记录使用antd-mobile时发现我之前配置的postcss失效了,防止大家踩坑,特此把解决方案分享到脚本之家平台,需要的朋友参考下吧...2021-06-21使用 React 和 Threejs 创建一个VR全景项目的过程详解
这篇文章主要介绍了使用 React 和 Threejs 创建一个VR全景项目的过程详解,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-04-06- 思路其实没有那么复杂,把地图想成一个盒子容器,地图中心点想成盒子中心点;扎点在【地图中心点】不会动,当移动地图时,去获取【地图中心点】经纬度,设置某个位置的时候,将经纬度设置为【地图中心点】即可...2021-06-20
- 这篇文章主要为大家详细介绍了React列表栏及购物车组件使用,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-06-28
- 这篇文章主要介绍了react使用antd表单赋值,用于修改弹框的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-10-29
- 这篇文章主要介绍了React Native 启动流程简析,文以 react-native-cli 创建的示例工程(安卓部分)为例,给大家分析 React Native 的启动流程,需要的朋友可以参考下...2021-08-18
- 这篇文章主要介绍了一百多行代码实现react拖拽hooks,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-21
- useState 通过在函数组件里调用它来给组件添加一些内部 state,React 会在重复渲染时保留这个 state,接下来通过一个示例来看看怎么使用 useState吧...2021-06-04
- 高阶组件就是接受一个组件作为参数并返回一个新组件(功能增强的组件)的函数。这里需要注意高阶组件是一个函数,并不是组件,这一点一定要注意,本文给大家分享React 高阶组件HOC使用小结,一起看看吧...2021-06-13
- 这篇文章主要介绍了React中使用setInterval函数的实例,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-04-06
关于antd tree和父子组件之间的传值问题(react 总结)
这篇文章主要介绍了关于antd tree 和父子组件之间的传值问题,是小编给大家总结的一些react知识点,本文通过一个项目需求实例代码详解给大家介绍的非常详细,需要的朋友可以参考下...2021-06-02- C# Hook钩子实例代码之截取键盘输入,需要的朋友可以参考下...2020-06-25
- 本文主要介绍了react为什么不推荐使用index作为key,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-07-22
- 钩子方法即是在普通的方法上添加"钩子",使特定事件发生时可以被调用,下面就来以实例讲解Ruby中的钩子方法及对方法调用添加钩子...2020-06-30
- Drupal可以让第三方模块创建自己的钩子。在通常的实践中,有两种类型的钩子你可能想要创建,一种是内容修改类的钩子,一种是拦截类的钩子。 Drupal的钩子系统允许和模...2016-11-25
- 这篇文章主要介绍了react自动化构建路由的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-04-23
- 这篇文章主要介绍了React Class组件生命周期,包括react组件的两种定义方式和class组件不同阶段生命周期函数执行顺序,本文给大家介绍的非常详细,需要的朋友可以参考下...2021-08-14
- 这篇文章主要介绍了react+ts实现简单jira项目,本文通过图文实例相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-07-30