【发布时间】:2021-12-30 12:51:30
【问题描述】:
有很多关于如何确定组件是否已卸载的线程,但如果您要确定组件是否已被重新安装,则其中很少有非常有用的线程 - 本质上是清除国家。我找到了one thread describing my issue almost to the letter,但没有给出好的策略来帮助我找到有问题的代码。
有什么好方法可以确定是否发生了卸载和装载?
【问题讨论】:
标签: reactjs debugging react-router
有很多关于如何确定组件是否已卸载的线程,但如果您要确定组件是否已被重新安装,则其中很少有非常有用的线程 - 本质上是清除国家。我找到了one thread describing my issue almost to the letter,但没有给出好的策略来帮助我找到有问题的代码。
有什么好方法可以确定是否发生了卸载和装载?
【问题讨论】:
标签: reactjs debugging react-router
我用来确定要卸载哪个组件的解决方案是在每个组件中添加对调试实用程序的调用。这是很容易显示罪魁祸首的实际示例输出:
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 功能组件是 created in the render phase 的唯一相关线程。
【讨论】: