likes
comments
collection
share

从源码的角度告诉你:为什么不能在render里面去触发更新

作者站长头像
站长
· 阅读数 41

一、情景再现

对于使用过React的小伙伴来说,肯定都知道下面这个现象:

从源码的角度告诉你:为什么不能在render里面去触发更新

这意味着我们的组件触发了无限循环更新,导致React给出了这个错误。那React官方是如何实现检测无限循环更新的功能的呢?我们以class组件为例,这次小编带着大家一次看个透。

二、源码解析

从这个报错信息我们可以看出,最后是checkForNestedUpdates函数抛出来的错误。此函数的源码如下:

function checkForNestedUpdates() {
    if (nestedUpdateCount > NESTED_UPDATE_LIMIT) {
      nestedUpdateCount = 0;
      rootWithNestedUpdates = null;

      {
        {
          throw Error( "Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops." );
        }
      }
    }

    {
      if (nestedPassiveUpdateCount > NESTED_PASSIVE_UPDATE_LIMIT) {
        nestedPassiveUpdateCount = 0;

        error('Maximum update depth exceeded. This can happen when a component ' + "calls setState inside useEffect, but useEffect either doesn't " + 'have a dependency array, or one of the dependencies changes on ' + 'every render.');
      }
    }
  }

React源码真是一个教科书级别的源码,跟其他的库比起来,React源码要易读很多,这并不是React源码足够简单,而是因为React的变量名的取义真是做到了极致。

你都不用看源码,这个函数名checkForNestedUpdates(检测嵌套的更新)就已经全撂了。

React17版本里,NESTED_UPDATE_LIMIT的值是50,意味着如果你的组件在一次渲染或者操作中触发了超过50次的更新,React官方会认为你这个组件是有问题的,从而给你抛出错误。

从源码的角度告诉你:为什么不能在render里面去触发更新

接下来,最大的问题就是React官方是如何标记更新次数的呢?

如何标记更新次数

从上述源码我们知道,标记更新次数其实就是看看nestedUpdateCount的值是在什么时候开始变化的。经过 代码跟踪 + ctrl+f,我们发现在 commitRootImpl 这个函数里会进行更新次数的累加。

从源码的角度告诉你:为什么不能在render里面去触发更新

commitRootImpl函数可是干了很多事情,所以我决定将它放到另一篇文章里讲一下。这里我们只需要知道这样的流程就可以:

1、产生更新
2、scheduleUpdateOnFiber
3、commitRootImpl(每调用一次,数量+1
4、checkForNestedUpdates
5if 更新数量 > 阈值50throw error

三、最后

好啦,本期文章到这里就结束啦,希望我讲的对你有帮助,那么下期再见啦~~

转载自:https://juejin.cn/post/7256255856152215609
评论
请登录