【问题标题】:React infinite update loop with useCallback (react-hooks/exhaustive-deps)使用 useCallback 反应无限更新循环(react-hooks/exhaustive-deps)
【发布时间】:2020-01-29 03:59:53
【问题描述】:

考虑以下呈现iframes 列表的示例。

我想将渲染后的iframes 的所有documents 存储在frames 中。

import React, { useState, useEffect, useCallback } from "react";
import Frame, { FrameContextConsumer } from "react-frame-component";

function MyFrame({ id, document, setDocument }) {
  useEffect(() => {
    console.log(`Setting the document for ${id}`);
    setDocument(id, document);
  }, [id, document]); // Caution: Adding `setDocument` to the array causes an infinite update loop!

  return <h1>{id}</h1>;
}

export default function App() {
  const [frames, setFrames] = useState({
    desktop: {
      name: "Desktop"
    },
    mobile: {
      name: "Mobile"
    }
  });
  const setFrameDocument = useCallback(
    (id, document) => {
      setFrames({
        ...frames,
        [id]: {
          ...frames[id],
          document
        }
      });
    },
    [frames, setFrames]
  );

  console.log(frames);

  return (
    <div className="App">
      {Object.keys(frames).map(id => (
        <Frame key={id}>
          <FrameContextConsumer>
            {({ document }) => (
              <MyFrame
                id={id}
                document={document}
                setDocument={setFrameDocument}
              />
            )}
          </FrameContextConsumer>
        </Frame>
      ))}
    </div>
  );
}

这里有两个问题:

  1. react-hooks/exhaustive-deps 抱怨依赖数组中缺少 setDocument。但是,添加它会导致无限更新循环。
  2. 控制台日志记录frames 显示仅设置了移动设备的document。我希望桌面的document 也会被设置。

你会如何解决这个问题?

Codesandbox

【问题讨论】:

    标签: reactjs react-hooks


    【解决方案1】:
    const setFrameDocument = useCallback(
        (id, document) => setFrames((frames) => ({
          ...frames,
          [id]: {
            ...frames[id],
            document
          }
        })),
        []
      );
    

    https://codesandbox.io/s/gracious-wright-y8esd


    框架对象的引用由于状态的更新而不断变化。使用之前的实现(即依赖数组中的框架对象),它会引起连锁反应,导致组件重新渲染并导致框架对象获得新的引用。这将永远持续下去。

    仅使用 setFrames 函数(常量引用),这种连锁反应不会传播。 eslint 知道 setFrames 是一个常量引用,因此它不会向用户抱怨它从依赖数组中丢失。

    【讨论】:

    • 如果您解释了您的解决方案以及为什么空的依赖数组是正确的解决方案,这将非常有帮助
    • @asus 是的,添加了解释。
    猜你喜欢
    • 2020-11-20
    • 1970-01-01
    • 2021-04-15
    • 2021-06-06
    • 1970-01-01
    • 2021-05-23
    • 2020-05-01
    • 2020-03-03
    • 2020-06-08
    相关资源
    最近更新 更多