如何判断一个组件是否被重新挂载?

How to determine if a component has been remounted?

有很多关于如何确定组件是否已卸载的线程,但是如果您要确定组件是否已被卸载,那么其中很少有有用的线程重新安装 - 本质上是清除状态。我找到了 ,但没有提供好的策略来帮助我找到有问题的代码。

确定先卸载再装载的好方法是什么?

我用来确定正在卸载哪个组件的解决方案是在每个组件中添加对调试实用程序的调用。这是很容易显示罪魁祸首的实际示例输出:

TopLevelRoutes: #useEffect cleanup
debugging-utils.ts:20 ClientsTopRoute: rendering (total: #74
debugging-utils.ts:5 ClientsTopRoute, seconds since last mount: 118
debugging-utils.ts:20 Clients/Listings: rendering (total: #371
debugging-utils.ts:5 Clients/Listings, seconds since last mount: 0
Clients/Listing: totalRenders 371
Listings.tsx:230 Clients/Listings: viewClientDrawer false
debugging-utils.ts:20 Clients/Listings: rendering (total: #372
debugging-utils.ts:5 Clients/Listings, seconds since last mount: 0
Listings.tsx:99 Clients/Listing: totalRenders 372
Listings.tsx:230 Clients/Listings: viewClientDrawer false
debugging-utils.ts:10 Clients/Listings: #useEffect cleanup
debugging-utils.ts:10 ClientsTopRoute: #useEffect cleanup
index.tsx:34 TopLevelRoutes count: 120
debugging-utils.ts:20 ClientsTopRoute: rendering (total: #75
debugging-utils.ts:5 ClientsTopRoute, seconds since last mount: 118

您可以很容易地从这里发现 Clients/Listings 组件在其父 ClientsTopRoute.

的每次重新渲染时被卸载和安装

我通过将这个添加到每个可疑组件中得到了这个:

import { createRenderingInfoPrinter } from "../debugging-utils";

const debug = createRenderingInfoPrinter("ClientsTopRoute");

const ClientsTopRoute: React.FC = () => {
  debug();
  return <div> ...</div>

我创建的调试挂钩如下所示:

/* debugging-utils.ts */

import React from "react";

export function usePrintSecondsSinceLastMount(identifier: string) {
  const [seconds, setSeconds] = React.useState(0);
  console.debug(`${identifier}, seconds since last mount: ${seconds}`);

  React.useEffect(() => {
    const timer = setInterval(() => setSeconds(seconds + 1), 1000);
    return () => {
      console.debug(`${identifier}: #useEffect cleanup`);
      clearInterval(timer);
    };
  }, [seconds]);
}

export function createRenderingInfoPrinter(identifier: string) {
  let count = 0;
  return () => {
    count++;
    console.debug(`${identifier}: rendering (total: #${count}`);
    usePrintSecondsSinceLastMount(identifier);
  };
}

如果您不关心渲染的总数,您当然可以直接使用 usePrintSecondsSinceLastMount 挂钩。


为了完整起见,我卸载的情况是由于我的前辈留下的一段看起来不起眼的 React Router 代码:

这里的关键是 withRouter 创建的 HOC 组件在每次重新渲染时都会 重新创建 。因此,它们不与先前 VDOM 的子树共享任何内容,因此会卸载现有节点。简单地从渲染函数中提取 HOC,如 const Listing = withRouter(ClientsListingComponent),解决了这个问题。

这种情况类似于我在 JSX 功能组件 .

问题上找到的唯一相关线程