javascript React上下文重新呈现导致重复的数据层推送

ruoxqz4g  于 2022-12-17  发布在  Java
关注(0)|答案(1)|浏览(146)

我使用React上下文在应用中的特定旅程中传递数据,我发现在最后一步渲染到DOM并希望在useEffect中执行特定函数(它使数据层推送)时,兄弟组件导致重新渲染,并且该函数被多次触发。
所讨论的兄弟组件触发了一个保存在上下文中的函数,以更新上下文的一个值-这将导致上下文重新呈现,我相信这是我所有头痛的问题。
有没有一种方法可以解决这个问题,这样我确实触发了上下文值更新,但不会导致带有数据层推送的组件被重新呈现?
代码分解参见下文-Full codesandbox here
我的控制台日志显示,由于Wizard组件正在更新上下文值,因此重新呈现的次数是我预期的两倍。

我知道ObjectUpdater更新上下文会强制它重新呈现,但是我的印象是,如果memo Package 导出的GaPushComponent组件内部没有任何变化,它将停止重新呈现?或者它被强制重新呈现是因为父组件发生了变化?

额外研究我一直在深入研究这个问题,发现this article明确指出:

如果您在React上下文提供器上传递一个对象,并且它的任何属性都更新了,那么会发生什么情况?使用该上下文的任何组件都将重新呈现。
代码分解:

应用程序js

export default function App() {
  useEffect(() => console.log("App.js"), []);
  const [wizardOrNothing, setWizardOrNothing] = useState(null);
  const toggleWizard = () =>
    setWizardOrNothing((prev) => {
      return prev === null ? <Wizard /> : null;
    });

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <button onClick={toggleWizard}>Start</button>
      {wizardOrNothing}
    </div>
  );
}

我的上下文提供程序.js

const MyContextProvider = ({ children }) => {
  const [myVal, setMyVal] = useState(null);
  const [someObj, setSomeObj] = useState({});

  const updateMyVal = (val) => setMyVal(myVal);
  const updateSomeObj = (obj) => setSomeObj((prev) => ({ ...prev, ...obj }));

  useEffect(() => console.log("MyContext.js"), []);

  return (
    <AppContext.Provider
      value={{
        myVal,
        someObj,
        updateMyVal,
        updateSomeObj
      }}
    >
      {children}
    </AppContext.Provider>
  );
};

export default memo(MyContextProvider);

向导.js

const Wizard = () => {
  useEffect(() => console.log("Wizard.js"), []);

  return (
    <MyContextProvider>
      <GaPushComponent />
      <ObjectUpdater />
    </MyContextProvider>
  );
};

对象更新程序.js

const ObjectUpdater = () => {
  const appContext = useContext(AppContext);

  useEffect(() => {
    console.log("ObjectUpdater.js");
    appContext.updateSomeObj({ newData: "some new data" });
  }, []);

  return <div data-testid="object-updater" />;
};

export default memo(ObjectUpdater);

快速推进组件.js

const GaPushComponent = () => {
  useEffect(() => {
    console.log("GaPushComponent.js");

    console.warn("pushing data to GA...");
  }, []);

  return <div>My GA push component</div>;
};

export default memo(GaPushComponent);
z9ju0rcb

z9ju0rcb1#

有两件事

  • My App re-renders twice-这是设计的。我在你的演示中看到应用使用了React 18。在R18中,它在实际设置之前运行了一次设置和清理。所以你在那里看到的日志是正确的。在你所有的钩子上添加一个清理函数。你可以尝试降级到17,这将防止这种重新呈现(强烈建议不要太)。

注意事项:这仅在开发模式下(当StrictMode打开时)。这不会在生产版本中发生

  • 上下文提供程序不公开updateSomeObj

文章:

  • ReactJS:与效果同步
  • ReactJS:使用效果

相关问题