一、谬误复现
开发环境报如下谬误。
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.Call Stack checkForNestedUpdates website/./node_modules/react-dom/cjs/react-dom.development.js:4013:321 scheduleUpdateOnFiber website/./node_modules/react-dom/cjs/react-dom.development.js:3606:187 dispatchAction website/./node_modules/react-dom/cjs/react-dom.development.js:2689:115 eval website/./src/components/FileUpload.jsx:73:7 invokePassiveEffectCreate website/./node_modules/react-dom/cjs/react-dom.development.js:3960:1047 HTMLUnknownElement.callCallback website/./node_modules/react-dom/cjs/react-dom.development.js:657:119 Object.invokeGuardedCallbackDev website/./node_modules/react-dom/cjs/react-dom.development.js:677:45 invokeGuardedCallback website/./node_modules/react-dom/cjs/react-dom.development.js:696:126 flushPassiveEffectsImpl website/./node_modules/react-dom/cjs/react-dom.development.js:3968:212 unstable_runWithPriority website/./node_modules/scheduler/cjs/scheduler.development.js:465:16
二、谬误排查
- 通过正文代码的形式,发现出问题的中央,是
Assets
组件中援用的FileUpload
出了问题。正好最近也批改过FileUpload
组件。 - 通过sourcetree比照git记录,看
FileUpload
组件被批改了什么?如下图。 - 再比照谬误提醒中的形容,其中
componentWillUpdate or componentDidUpdate
,揣测就是指新增的useEffect
代码片断。 - 将上述
useEffect
代码片断正文掉,果然谬误隐没。
三、起因剖析
useEffect
的个性表明,只有initFiles
产生了扭转,46-48行代码就会执行。
既然上述useEffect
代码片断事实上造成了死循环,就还阐明了一点:
setFileList(initFiles)
扭转了initFiles
,才使得useEffect
中的函数再次被调用。
那么,initFiles
到底是经验了怎么的变动,才使得调用可能周而复始地产生呢?
输入fileList
和initFiles
:
console.log(fileList === initFiles)
能够发现,只有第一次render时输入true
,后续全副是false
。
- 第一次输入
true
,表明useState
的入参为array
时,只是简略的赋值关系,fileList
和initFiles
指定了同一个内存地址。 setFileList
函数实际上是做了一次浅拷贝,而后赋值给fileList
,扭转了fileList
的内存指向,也就是扭转了最新initFiles
的内存指向。同时React保留了之前initFiles
的值用来做依赖比照。useEffect
在比照援用类型的依赖,比方object/array
时,采纳的是简略的===
操作符,也就是说比拟内存地址是否统一。- 前后两次
initFiles
尽管外部数据雷同,但内存指向不同,就被useEffect
认为【依赖产生了扭转】,从而导致了死循环。
四、解决方案
尽量不间接应用object或者array作为依赖项,而是应用值类型来代替援用类型
useEffect(() => {//...}, [initFiles.length])
五、拓展
是不是在调用useState
时,拷贝initFiles
就能够了呢?
const [fileList, setFileList] = useState([...initFiles])useEffect(() => { if (fileList.length === 0) { setFileList([...initFiles]) }}, [initFiles])
这样仍然会报同样的死循环谬误,为什么?欢送大家留言探讨。