[dashboard] fix Memory leak when reset causes by-value panel to be deleted (#161394)

Closes https://github.com/elastic/kibana/issues/161310

Issue caused by `setState` call after async action without checking that
component is still mounted. Resolved issue by checking component is
mounted after any async action or subscription.

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Nathan Reese 2023-07-07 08:53:50 -06:00 committed by GitHub
parent cd24dc2254
commit d9c0c554f8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -157,9 +157,6 @@ export class EmbeddablePanel extends React.Component<Props, State> {
}
private async refreshBadges() {
if (!this.mounted) {
return;
}
if (this.props.showBadges === false) {
return;
}
@ -173,6 +170,10 @@ export class EmbeddablePanel extends React.Component<Props, State> {
embeddable: this.props.embeddable,
})) as BadgeAction[]) ?? [];
if (!this.mounted) {
return;
}
const { disabledActions } = this.props.embeddable.getInput();
if (disabledActions) {
badges = badges.filter((badge) => disabledActions.indexOf(badge.id) === -1);
@ -186,9 +187,6 @@ export class EmbeddablePanel extends React.Component<Props, State> {
}
private async refreshNotifications() {
if (!this.mounted) {
return;
}
if (this.props.showNotifications === false) {
return;
}
@ -202,6 +200,10 @@ export class EmbeddablePanel extends React.Component<Props, State> {
embeddable: this.props.embeddable,
})) as NotificationAction[]) ?? [];
if (!this.mounted) {
return;
}
const { disabledActions } = this.props.embeddable.getInput();
if (disabledActions) {
notifications = notifications.filter((badge) => disabledActions.indexOf(badge.id) === -1);
@ -353,20 +355,28 @@ export class EmbeddablePanel extends React.Component<Props, State> {
this.subscription.add(
this.props.embeddable.getOutput$().subscribe(
(output: EmbeddableOutput) => {
this.setState({
error: output.error,
loading: output.loading,
});
if (this.mounted) {
this.setState({
error: output.error,
loading: output.loading,
});
}
},
(error) => {
this.setState({ error });
if (this.mounted) {
this.setState({ error });
}
}
)
);
const node = this.props.embeddable.render(this.embeddableRoot.current) ?? undefined;
if (isPromise(node)) {
node.then((resolved) => this.setState({ node: resolved }));
node.then((resolved) => {
if (this.mounted) {
this.setState({ node: resolved });
}
});
} else {
this.setState({ node });
}