在React组件中运行以下代码时,将导致无限循环。为什么将数组作为依赖项传递给useEffect
(在这种情况下为args
)会导致这种情况发生?如何阻止无休止的循环发生?该代码只能运行一次。
我已阅读到可以使用[args.length]
阻止这种情况的发生,但是ESLint规则react-hooks/exhaustive-deps
会引发错误,因此我想避免这样做。
import React, { useEffect, useState } from 'react';
export default function Home() {
const args = ['a'];
const [value, setValue] = useState(['b']);
useEffect(() => {
setValue(['c']);
}, [args]);
console.log('value', value);
}
注意上面的代码中,我什至根本没有使用或修改args
回调中的useEffect
。
如果我将args
的值更改为一个字符串,例如const args = 'a'
,则没有无限循环。因此,当依赖项是数组时,似乎会出现问题。
答案 0 :(得分:1)
问题在于对args
的任何更改都会导致您的效果运行。此时,您setValue(args)
再次更改args
。这将使您的效果再次运行...从而形成无限循环。
如果将args
设置为相同的字符串,则如果它们按react检测到更改的方式匹配,则该字符串将不会被注册为更改。这不适用于数组或对象。 {test: 'a'} !== {test: 'a'}
和['a'] !== ['a']
,但'a' === 'a'
和1 === 1
。
我也遇到了你的问题。我最终禁用了react-hooks/exhaustive-deps
规则。但我有更多数据供您选择。我努力尝试使用此规则一段时间。
This post我提出的问题与您的问题非常相似。最终结果是您应该使用setState
作为函数(例如,您的示例中的setState(oldState => oldState)
),此时旧状态不需要是依赖项,也不需要useReducer
效果一样。
但是,这两种方法都不都是您尝试做的事情,这会带来更多问题,这在我稍后做的post中可以看到。如果它们是纯净的,那您就没事了。
1st post上的第四种解决方案描述了如何积极避免此问题,但是最终我决定使用react-hooks/exhaustive-deps
规则,并在我故意删除不依赖的依赖项时逐行禁用它想。我不同意这是否应成为规则。
您要解决的问题是React的useState
和useReducer
的要求与详尽的dep要求之间的平衡。我认为这导致了很多工作,要使这些要求超出实际生产力。
答案 1 :(得分:0)
使用useRef
为我解决了此问题:
const args = useRef(['a']);
const [value, setValue] = useState(['b']);
useEffect(() => {
setValue(['c']);
}, [args]);
console.log('value', value);
args
的值可以在useEffect
回调中与args.current
一起使用。