如何解决React useEffect钩子带来的无限循环问题

 更新时间:2022年07月07日 11:26:39   作者:前端修罗场  
本文主要介绍了解决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函数。因此,这会导致一个无限循环:

gif在这里插入图片描述

是什么导致了这个问题?让我们一步一步来分析这个问题:

  • 在第一次渲染时,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函数。

image

使用函数作为依赖项

如果你把一个方法传入你的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的值。

image

是什么导致了这个问题?

  • 要记住的一件事是,useEffect使用了一个叫做浅比较的概念。它这样做是为了验证依赖项是否已经更新
  • 这里的问题是,在每次呈现期间,React都会重新定义logResult的引用
  • 因此,这将在每个循环中重新触发useEffect函数
  • 因此,React会调用setCount钩子,直到应用程序遇到更新深度错误。这会给程序带来错误和不稳定性

如何解决这个问题

一个解决方案是使用useCallback钩子。这允许开发人员记住他们的函数,从而确保引用值保持不变。由于这个参考值是稳定的,React不应该无限地重新渲染UI:

const logResult = useCallback(() => {
  return 2 + 2;
}, []); // logResult是缓存的
useEffect(()=> {
  setCount((count)=> count+1);
},[logResult]); //没有无限循环错误,因为logResult引用保持不变。

结果:

image

使用数组作为依赖项

将数组变量传递给依赖项也会运行一个无限循环。考虑下面的代码示例:

const [count, setCount] = useState(0); //初始值为0。
const myArray = ["one", "two", "three"];

useEffect(() => {
  setCount((count) => count + 1); // 和前面一样,增加Count的值
}, [myArray]); // 将数组变量传递给依赖项

在这个块中,我们将myArray变量传入依赖参数。

gif

是什么导致了这个问题?

既然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>
);

控制台的结果表明程序是无限循环的:

img

是什么导致了这个问题?

  • 和之前一样,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>
);

gif

是什么导致了这个问题?

  • 在上面的代码中,我们告诉在useEffect方法中更新count的值
  • 此外,注意我们也将count Hook传递给了它的依赖数组
  • 这意味着每次count值更新时,React都会调用useEffect
  • 因此,useEffect钩子调用setCount,从而再次更新count
  • 因此,React现在在一个无限循环中运行我们的函数

如何解决这个问题

要摆脱无限循环,只需像这样使用一个空的依赖数组:

const [count, setCount] = useState(0);
// 只有在组件首次挂载时才更新'count'的值
useEffect(() => {
  setCount((count) => count + 1);
}, []);

这将告诉React在第一次渲染时运行useEffect。

gif

结尾

尽管React Hooks是一个简单的概念,但是在将它们整合到项目中时,仍然需要记住许多规则。这将确保您的应用程序保持稳定,优化,并在生产过程中不抛出错误。

此外,最近发布的Create React App CLI也会在运行时检测和报告无限循环错误。这有助于开发人员在这些问题出现在生产服务器上之前发现并解决这些问题。

img

 到此这篇关于如何解决React useEffect钩子带来的无限循环问题的文章就介绍到这了,更多相关React useEffect钩子无限循环内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 使用React+ts实现无缝滚动的走马灯详细过程

    使用React+ts实现无缝滚动的走马灯详细过程

    这篇文章主要给大家介绍了关于使用React+ts实现无缝滚动的走马灯详细过程,文中给出了详细的代码示例以及图文教程,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2023-08-08
  • 深入了解响应式React Native Echarts组件

    深入了解响应式React Native Echarts组件

    近年来,随着移动端对数据可视化的要求越来越高,通过 WebView 在移动端使用 Echarts 这样功能强大的前端数据可视化库,是解决问题的好办法。下面就和小编来一起学习一下吧
    2019-05-05
  • React+Webpack快速上手指南(小结)

    React+Webpack快速上手指南(小结)

    这篇文章主要介绍了React+Webpack快速上手指南(小结),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-08-08
  • React Hook - 自定义Hook的基本使用和案例讲解

    React Hook - 自定义Hook的基本使用和案例讲解

    自定义Hook本质上只是一种函数代码逻辑的抽取,严格意义上来说,它本身并不算React的特性,这篇文章主要介绍了React类组件和函数组件对比-Hooks的介绍及初体验,需要的朋友可以参考下
    2022-11-11
  • 使用react的7个避坑案例小结

    使用react的7个避坑案例小结

    React是个很受欢迎的前端框架。今天我们探索下React开发者应该注意的七点,感兴趣的小伙伴们可以参考一下
    2021-05-05
  • 详解react-router-dom v6版本基本使用介绍

    详解react-router-dom v6版本基本使用介绍

    本文主要介绍了react-router-dom v6版本基本使用介绍,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • React特征学习Form数据管理示例详解

    React特征学习Form数据管理示例详解

    这篇文章主要为大家介绍了React特征学习Form数据管理示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-09-09
  • 详解在React项目中安装并使用Less(用法总结)

    详解在React项目中安装并使用Less(用法总结)

    这篇文章主要介绍了详解在React项目中安装并使用Less(用法总结),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-03-03
  • 利用ES6语法重构React组件详解

    利用ES6语法重构React组件详解

    这篇文章主要介绍了利用ES6语法重构React组件的相关资料,文中通过示例代码介绍的很详细,对大家具有一定的参考借鉴价值,需要的朋友们下面来一起看看吧。
    2017-03-03
  • React Hooks useReducer 逃避deps组件渲染次数增加陷阱

    React Hooks useReducer 逃避deps组件渲染次数增加陷阱

    这篇文章主要介绍了React Hooks 之 useReducer 逃避deps后增加组件渲染次数的陷阱详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-09-09

最新评论