Commit 0216f087 by Torkel Ödegaard Committed by GitHub

Merge pull request #15113 from grafana/fix/explore-set-state-on-unmounted

Fix setState on unmounted component in Loki and Prometheus QueryField
parents cab1e944 27948b13
// https://github.com/facebook/react/issues/5465
export interface CancelablePromise<T> {
promise: Promise<T>;
cancel: () => void;
}
export const makePromiseCancelable = <T>(promise: Promise<T>): CancelablePromise<T> => {
let hasCanceled_ = false;
const wrappedPromise = new Promise<T>((resolve, reject) => {
promise.then(val => (hasCanceled_ ? reject({ isCanceled: true }) : resolve(val)));
promise.catch(error => (hasCanceled_ ? reject({ isCanceled: true }) : reject(error)));
});
return {
promise: wrappedPromise,
cancel() {
hasCanceled_ = true;
},
};
};
......@@ -16,6 +16,7 @@ import RunnerPlugin from 'app/features/explore/slate-plugins/runner';
// Types
import { LokiQuery } from '../types';
import { TypeaheadOutput } from 'app/types/explore';
import { makePromiseCancelable, CancelablePromise } from 'app/core/utils/CancelablePromise';
const PRISM_SYNTAX = 'promql';
......@@ -85,6 +86,7 @@ class LokiQueryField extends React.PureComponent<LokiQueryFieldProps, LokiQueryF
languageProvider: any;
modifiedSearch: string;
modifiedQuery: string;
languageProviderInitializationPromise: CancelablePromise<any>;
constructor(props: LokiQueryFieldProps, context) {
super(props, context);
......@@ -112,12 +114,24 @@ class LokiQueryField extends React.PureComponent<LokiQueryFieldProps, LokiQueryF
componentDidMount() {
if (this.languageProvider) {
this.languageProvider
.start()
this.languageProviderInitializationPromise = makePromiseCancelable(this.languageProvider.start());
this.languageProviderInitializationPromise.promise
.then(remaining => {
remaining.map(task => task.then(this.onUpdateLanguage).catch(() => {}));
})
.then(() => this.onUpdateLanguage());
.then(() => this.onUpdateLanguage())
.catch(({ isCanceled }) => {
if (isCanceled) {
console.warn('LokiQueryField has unmounted, language provider intialization was canceled');
}
});
}
}
componentWillUnmount() {
if (this.languageProviderInitializationPromise) {
this.languageProviderInitializationPromise.cancel();
}
}
......
......@@ -12,6 +12,7 @@ import BracesPlugin from 'app/features/explore/slate-plugins/braces';
import RunnerPlugin from 'app/features/explore/slate-plugins/runner';
import QueryField, { TypeaheadInput, QueryFieldState } from 'app/features/explore/QueryField';
import { PromQuery } from '../types';
import { CancelablePromise, makePromiseCancelable } from 'app/core/utils/CancelablePromise';
const HISTOGRAM_GROUP = '__histograms__';
const METRIC_MARK = 'metric';
......@@ -104,6 +105,7 @@ interface PromQueryFieldState {
class PromQueryField extends React.PureComponent<PromQueryFieldProps, PromQueryFieldState> {
plugins: any[];
languageProvider: any;
languageProviderInitializationPromise: CancelablePromise<any>;
constructor(props: PromQueryFieldProps, context) {
super(props, context);
......@@ -129,12 +131,23 @@ class PromQueryField extends React.PureComponent<PromQueryFieldProps, PromQueryF
componentDidMount() {
if (this.languageProvider) {
this.languageProvider
.start()
this.languageProviderInitializationPromise = makePromiseCancelable(this.languageProvider.start());
this.languageProviderInitializationPromise.promise
.then(remaining => {
remaining.map(task => task.then(this.onUpdateLanguage).catch(() => {}));
})
.then(() => this.onUpdateLanguage());
.then(() => this.onUpdateLanguage())
.catch(({ isCanceled }) => {
if (isCanceled) {
console.warn('PromQueryField has unmounted, language provider intialization was canceled');
}
});
}
}
componentWillUnmount() {
if (this.languageProviderInitializationPromise) {
this.languageProviderInitializationPromise.cancel();
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment