我使用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);
1条答案
按热度按时间z9ju0rcb1#
有两件事
My App re-renders twice
-这是设计的。我在你的演示中看到应用使用了React 18。在R18中,它在实际设置之前运行了一次设置和清理。所以你在那里看到的日志是正确的。在你所有的钩子上添加一个清理函数。你可以尝试降级到17,这将防止这种重新呈现(强烈建议不要太)。注意事项:这仅在开发模式下(当
StrictMode
打开时)。这不会在生产版本中发生updateSomeObj
。文章: