当更新不在依赖列表中的变量时调用 useEffect(导致无限循环)

useEffect called when a variable not in the dependancy list is updated (causing an infinite loop)

我正在尝试在状态更改时执行 ajax 调用,然后将另一个状态设置为该 ajax 调用的结果。

const [plc, setPlc] = useState(null);
const [tags, setTags] = useState([]);

...

useEffect(()=>{
  if(plc != null) {
    myAjaxPromiseFunction(plc).catch((err)=>{
      console.log(err);
    }).then((tags)=>{
      setTags(tags);
    });
  }
}, [plc]);

出于某种原因,这会导致无限循环。但是,当我删除 setTags(tags); 语句时,它会按预期工作。似乎 setTags 函数导致效果挂钩更新,但 tags 不是此效果挂钩的依赖项的一部分。

仅供参考,tags 变量应该是一个对象列表。

编辑:

我的代码中还有一个 useEffect

useEffect(() => { // Update which tags are logged
  if(plc != null) {
    anotherAjaxFunction(plc, tags).catch(err => {
      toaster.show({
        message: err,
        intent: "danger"
      });
    }).then(tags => {
      setTags(tags);
    });
  }
}, [plc, updateLoggedFlag]);

然而,这个useEffect不依赖于tags,如果我删除这段代码,问题仍然存在。

旁注: updateLoggedFlag 是我计划用来强制效果根据需要更新的变量,但我还没有在任何地方使用它.

另一个编辑: Link 使用代码沙箱进行复制:https://codesandbox.io/s/cranky-ives-3xyrq?file=/src/App.js

有什么想法吗?感谢您的帮助。

我认为您的代码存在的问题是它没有在依赖数组中包含标签。从概念上讲,这应该可以正常工作,正如其他开发人员之前提到的那样,但是 React 文档指出,回调中使用的所有状态变量和道具都应该存在于依赖数组中,否则会导致错误。在这里看看。 Hooks FAQ

简而言之:将 TagColumn 移到 App 之外,因为它是 here


问题与效果声明无关,而是由于组件声明。

在您的沙箱中,TagColumn 是在 App 中定义的。这意味着每次渲染 App 时(特别是每次更改其状态时),都会为 const TagColumn 分配不同的值。 React 无法每次都看到它是相同的组件 - 毕竟,它并不完全相同,因为捕获的范围在变化。
因此,App 呈现一个新的 TagColumn。 React 看到组件是从头开始创建的,渲染它,特别是调用它的钩子,包括每个 useEffect。在 useEffect 中,您使用回调来更改 App 的状态。 App 重新渲染,创建 另一个 组件 TagColumn,这是它生命中的第一次再次渲染,调用每个 useEffect... 和循环继续。

一般来说,您不应在功能组件范围内捕获任何非常量。相反:

  • 如果该值是由外部上下文生成的(App,在这种情况下)——将其作为道具传递;
  • 如果该值由组件本身生成 - 根据需要使用 useStateuseRef 或其他挂钩。