等效于开发模式下严格模式的第一渲染钩子

  • 本文关键字:模式 于开发 开发 reactjs
  • 更新时间 :
  • 英文 :


以前我使用过这样的钩子来确定组件是否是第一次渲染:

function useIsFirstRender() {
const isFirst = useRef(true);
if (isFirst.current) {
isFirst.current = false;
return true;
}
return isFirst.current;
}
function App() {
const isFirstRender = useIsFirstRender();
useEffect(() => {
if (isFirstRender) {
// It's the first render
}
}, []); // I'd expect [] to cause useEffect's first param to be called once, but with StrictMode this doesn't happen.
}

自从在 React 18 中开始使用 StrictMode 以来,这个钩子不再像我预期的那样起作用,因为我的组件由于 StrictMode 在开发中的工作方式而被渲染了两次,并且在两个渲染上都trueisFirstRender。相反,我必须按照 https://github.com/reactwg/react-18/discussions/18 直接在每个组件中实现useRef

function App() {
const isFirstRender = useRef(true);
useEffect(() => {
if (isFirstRender.current === true) {
isFirstRender.current = false;
// It's the first render
}
}, []);
}

我希望制作另一个可重用的钩子,这样我就不需要在需要此行为的每个组件中重新实现useRef逻辑。

我知道这种双重渲染行为只发生在开发模式下。但是,我只想在第一次渲染时执行的一些操作涉及调用非幂等的 API,因此在开发过程中,这让事情变得非常困难。

这种useFirstRender钩呢?这可以在每个组件中重用,其回调仅在第一次渲染时调用。卸载后,它还会在重新安装时再次调用一次。

更新 1:为了澄清起见,这实际上是在第二次渲染上运行的,因为我认为严格模式添加的第一个渲染不是你感兴趣的,但显然可以修改它以在 react 18 严格模式的第一个渲染上运行并忽略第二个。我不知道哪一个对你更有意义。

更新 2:我不知道为什么我认为诚实地运行第二次运行是个好主意,因为根据 reactwg 讨论,额外的运行是第二次运行。我将其更改为在实际的第一次渲染上运行,而不是更多:) 如果卸载,然后再次重新挂载它只会触发一次回调。

function useFirstRender(callback) {
const isFirst = useRef(false);
if (!isFirst.current) {
isFirst.current = true;
}
useEffect(() => {
if (isFirst.current) {
callback();
}
return () => {
isFirst.current = false;
};
}, []);
}
function Component() {
useFirstRender(() => {
console.log('Rendered first time');
});
return <div>Component</div>;
}
function App() {
return (
<React.StrictMode>
<Component/>
</React.StrictMode>
);
}

这听起来是一个奇怪的问题,因为将空数组作为useEffect的第二个参数传递具有您所要求的效果,不需要更多。

难道问题不是代码运行两次,而是您的组件被卸载并再次挂载?

我建议您向组件添加以下代码,以检测是否是这种情况:

function App() {
// Add this
let counterA = 0;
let counterB = 0;
useEffect(() => {
console.log("counterA", counterA++);
return () => console.log("counterB", counterB++);
}, []);
// Follows the rest of your code
}

在我的控制台中,我只能看到卸载组件时counterA 0及以后的counterB 0

如果你看到counterA 1counterA 2等... 问题超出了我的知识范围,你可以忽略这个答案; 但是如果你能多次看到counterA 0counterB 0,React.js按预期工作,可能你必须重新考虑控制调用 API 的方式和时间;上下文可能会对您有所帮助。

React.js在 StrictMode开发环境中运行一些代码两次(作为setState函数)的原因正是为了帮助我们检测不良的实现。寻求避免这种障碍的方法,目的是自由地做糟糕的实现,这听起来是一个非常糟糕的主意。;)

编辑:我将用于测试此的应用程序更新为最新版本和最新的最佳实践,并且(仅在开发环境中)我看到快速顺序counterA 0counterB 0counterA 1:是时候重构我的一些代码了!

最新更新