从源码的角度告诉你:为什么不能在render里面去触发更新
一、情景再现
对于使用过React的小伙伴来说,肯定都知道下面这个现象:
这意味着我们的组件触发了无限循环更新
,导致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官方会认为你这个组件是有问题的,从而给你抛出错误。
接下来,最大的问题就是React官方是如何标记更新次数的呢?
如何标记更新次数
从上述源码我们知道,标记更新次数
其实就是看看nestedUpdateCount
的值是在什么时候开始变化的。经过 代码跟踪
+ ctrl+f
,我们发现在 commitRootImpl
这个函数里会进行更新次数的累加。
commitRootImpl
函数可是干了很多事情,所以我决定将它放到另一篇文章里讲一下。这里我们只需要知道这样的流程就可以:
1、产生更新
2、scheduleUpdateOnFiber
3、commitRootImpl(每调用一次,数量+1)
4、checkForNestedUpdates
5、if 更新数量 > 阈值50,throw error
三、最后
好啦,本期文章到这里就结束啦,希望我讲的对你有帮助,那么下期再见啦~~
转载自:https://juejin.cn/post/7256255856152215609