Commit 64023916 by Andrej Ocenas Committed by GitHub

Explore: Add memoization and remove unused props (#18775)

parent 3aa3a453
......@@ -208,6 +208,7 @@
"jquery": "3.4.1",
"lodash": "4.17.14",
"marked": "0.6.2",
"memoize-one": "5.1.1",
"moment": "2.24.0",
"mousetrap": "1.6.3",
"mousetrap-global-bind": "1.1.0",
......
......@@ -5,7 +5,9 @@ const INTERVAL = 150;
export interface Props {
time?: number;
renderCount?: number;
// Use this to reset the timer. Any value is allowed just need to be !== from the previous.
// Keep in mind things like [] !== [] or {} !== {}.
resetKey?: any;
className?: string;
humanize?: boolean;
}
......@@ -14,6 +16,9 @@ export interface State {
elapsed: number;
}
/**
* Shows an incremental time ticker of elapsed time from some event.
*/
export default class ElapsedTime extends PureComponent<Props, State> {
offset: number;
timer: number;
......@@ -40,7 +45,7 @@ export default class ElapsedTime extends PureComponent<Props, State> {
this.start();
}
if (nextProps.renderCount) {
if (nextProps.resetKey !== this.props.resetKey) {
clearInterval(this.timer);
this.start();
}
......
......@@ -5,6 +5,7 @@ import { hot } from 'react-hot-loader';
import { connect } from 'react-redux';
import _ from 'lodash';
import { AutoSizer } from 'react-virtualized';
import memoizeOne from 'memoize-one';
// Services & Utils
import store from 'app/core/store';
......@@ -327,6 +328,9 @@ export class Explore extends React.PureComponent<ExploreProps> {
}
}
const ensureQueriesMemoized = memoizeOne(ensureQueries);
const getTimeRangeFromUrlMemoized = memoizeOne(getTimeRangeFromUrl);
function mapStateToProps(state: StoreState, { exploreId }: ExploreProps) {
const explore = state.explore;
const { split } = explore;
......@@ -356,8 +360,8 @@ function mapStateToProps(state: StoreState, { exploreId }: ExploreProps) {
const { datasource, queries, range: urlRange, mode: urlMode, ui } = (urlState || {}) as ExploreUrlState;
const initialDatasource = datasource || store.get(lastUsedDatasourceKeyForOrgId(state.user.orgId));
const initialQueries: DataQuery[] = ensureQueries(queries);
const initialRange = urlRange ? getTimeRangeFromUrl(urlRange, timeZone).raw : DEFAULT_RANGE;
const initialQueries: DataQuery[] = ensureQueriesMemoized(queries);
const initialRange = urlRange ? getTimeRangeFromUrlMemoized(urlRange, timeZone).raw : DEFAULT_RANGE;
let newMode: ExploreMode;
if (supportedModes.length) {
......
import React, { PureComponent } from 'react';
import { connect } from 'react-redux';
import { hot } from 'react-hot-loader';
import memoizeOne from 'memoize-one';
import { ExploreId, ExploreMode } from 'app/types/explore';
import { DataSourceSelectItem, ToggleButtonGroup, ToggleButton } from '@grafana/ui';
......@@ -236,27 +237,11 @@ export class UnConnectedExploreToolbar extends PureComponent<Props, {}> {
}
}
const mapStateToProps = (state: StoreState, { exploreId }: OwnProps): StateProps => {
const splitted = state.explore.split;
const exploreItem = state.explore[exploreId];
const {
datasourceInstance,
datasourceMissing,
exploreDatasources,
range,
refreshInterval,
loadingState,
supportedModes,
mode,
isLive,
} = exploreItem;
const selectedDatasource = datasourceInstance
? exploreDatasources.find(datasource => datasource.name === datasourceInstance.name)
: undefined;
const loading = loadingState === LoadingState.Loading || loadingState === LoadingState.Streaming;
const hasLiveOption =
datasourceInstance && datasourceInstance.meta && datasourceInstance.meta.streaming ? true : false;
const getModeOptionsMemoized = memoizeOne(
(
supportedModes: ExploreMode[],
mode: ExploreMode
): [Array<SelectableValue<ExploreMode>>, SelectableValue<ExploreMode>] => {
const supportedModeOptions: Array<SelectableValue<ExploreMode>> = [];
let selectedModeOption = null;
for (const supportedMode of supportedModes) {
......@@ -283,6 +268,32 @@ const mapStateToProps = (state: StoreState, { exploreId }: OwnProps): StateProps
break;
}
}
return [supportedModeOptions, selectedModeOption];
}
);
const mapStateToProps = (state: StoreState, { exploreId }: OwnProps): StateProps => {
const splitted = state.explore.split;
const exploreItem = state.explore[exploreId];
const {
datasourceInstance,
datasourceMissing,
exploreDatasources,
range,
refreshInterval,
loadingState,
supportedModes,
mode,
isLive,
} = exploreItem;
const selectedDatasource = datasourceInstance
? exploreDatasources.find(datasource => datasource.name === datasourceInstance.name)
: undefined;
const loading = loadingState === LoadingState.Loading || loadingState === LoadingState.Streaming;
const hasLiveOption =
datasourceInstance && datasourceInstance.meta && datasourceInstance.meta.streaming ? true : false;
const [supportedModeOptions, selectedModeOption] = getModeOptionsMemoized(supportedModes, mode);
return {
datasourceMissing,
......
......@@ -40,28 +40,10 @@ export interface Props extends Themeable {
stopLive: () => void;
}
export interface State {
renderCount: number;
}
class LiveLogs extends PureComponent<Props, State> {
class LiveLogs extends PureComponent<Props> {
private liveEndDiv: HTMLDivElement = null;
constructor(props: Props) {
super(props);
this.state = { renderCount: 0 };
}
componentDidUpdate(prevProps: Props) {
const prevRows: LogRowModel[] = prevProps.logsResult ? prevProps.logsResult.rows : [];
const rows: LogRowModel[] = this.props.logsResult ? this.props.logsResult.rows : [];
if (prevRows !== rows) {
this.setState({
renderCount: this.state.renderCount + 1,
});
}
if (this.liveEndDiv) {
this.liveEndDiv.scrollIntoView(false);
}
......@@ -69,7 +51,6 @@ class LiveLogs extends PureComponent<Props, State> {
render() {
const { theme, timeZone } = this.props;
const { renderCount } = this.state;
const styles = getStyles(theme);
const rowsToRender: LogRowModel[] = this.props.logsResult ? this.props.logsResult.rows : [];
const showUtc = timeZone === 'utc';
......@@ -109,7 +90,7 @@ class LiveLogs extends PureComponent<Props, State> {
</div>
<div className={cx([styles.logsRowsIndicator])}>
<span>
Last line received: <ElapsedTime renderCount={renderCount} humanize={true} /> ago
Last line received: <ElapsedTime resetKey={this.props.logsResult} humanize={true} /> ago
</span>
<LinkButton
onClick={this.props.stopLive}
......
......@@ -39,7 +39,6 @@ interface Props {
scanning?: boolean;
scanRange?: RawTimeRange;
dedupStrategy: LogsDedupStrategy;
hiddenLogLevels: Set<LogLevel>;
onChangeTime: (range: AbsoluteTimeRange) => void;
onClickLabel?: (label: string, value: string) => void;
onStartScanning?: () => void;
......
......@@ -43,7 +43,6 @@ interface LogsContainerProps {
toggleLogLevelAction: typeof toggleLogLevelAction;
changeDedupStrategy: typeof changeDedupStrategy;
dedupStrategy: LogsDedupStrategy;
hiddenLogLevels: Set<LogLevel>;
width: number;
isLive: boolean;
stopLive: typeof changeRefreshIntervalAction;
......@@ -100,7 +99,6 @@ export class LogsContainer extends PureComponent<LogsContainerProps> {
scanning,
range,
width,
hiddenLogLevels,
isLive,
} = this.props;
......@@ -131,7 +129,6 @@ export class LogsContainer extends PureComponent<LogsContainerProps> {
scanning={scanning}
scanRange={range.raw}
width={width}
hiddenLogLevels={hiddenLogLevels}
getRowContext={this.getLogRowContext}
/>
</Collapse>
......@@ -155,7 +152,6 @@ function mapStateToProps(state: StoreState, { exploreId }: { exploreId: string }
} = item;
const loading = loadingState === LoadingState.Loading || loadingState === LoadingState.Streaming;
const { dedupStrategy } = exploreItemUIStateSelector(item);
const hiddenLogLevels = new Set(item.hiddenLogLevels);
const dedupedResult = deduplicatedLogsSelector(item);
const timeZone = getTimeZone(state.user);
......@@ -166,7 +162,6 @@ function mapStateToProps(state: StoreState, { exploreId }: { exploreId: string }
scanning,
timeZone,
dedupStrategy,
hiddenLogLevels,
dedupedResult,
datasourceInstance,
isLive,
......
......@@ -2,6 +2,7 @@
import React, { PureComponent } from 'react';
import _ from 'lodash';
import { hot } from 'react-hot-loader';
import memoizeOne from 'memoize-one';
// @ts-ignore
import { connect } from 'react-redux';
......@@ -13,7 +14,7 @@ import { changeQuery, modifyQueries, runQueries, addQueryRow } from './state/act
// Types
import { StoreState } from 'app/types';
import { TimeRange, AbsoluteTimeRange, toDataFrame, guessFieldTypes } from '@grafana/data';
import { TimeRange, AbsoluteTimeRange, toDataFrame, guessFieldTypes, GraphSeriesXY, LoadingState } from '@grafana/data';
import { DataQuery, DataSourceApi, QueryFixAction, DataSourceStatus, PanelData, DataQueryError } from '@grafana/ui';
import { HistoryItem, ExploreItemState, ExploreId, ExploreMode } from 'app/types/explore';
import { Emitter } from 'app/core/utils/emitter';
......@@ -198,6 +199,17 @@ export class QueryRow extends PureComponent<QueryRowProps, QueryRowState> {
}
}
const makeQueryResponseMemoized = memoizeOne(
(graphResult: GraphSeriesXY[], error: DataQueryError, loadingState: LoadingState): PanelData => {
const series = graphResult ? graphResult.map(serie => guessFieldTypes(toDataFrame(serie))) : []; // TODO: use DataFrame
return {
series,
state: loadingState,
error,
};
}
);
function mapStateToProps(state: StoreState, { exploreId, index }: QueryRowProps) {
const explore = state.explore;
const item: ExploreItemState = explore[exploreId];
......@@ -217,12 +229,7 @@ function mapStateToProps(state: StoreState, { exploreId, index }: QueryRowProps)
const query = queries[index];
const datasourceStatus = datasourceError ? DataSourceStatus.Disconnected : DataSourceStatus.Connected;
const error = queryErrors.filter(queryError => queryError.refId === query.refId)[0];
const series = graphResult ? graphResult.map(serie => guessFieldTypes(toDataFrame(serie))) : []; // TODO: use DataFrame
const queryResponse: PanelData = {
series,
state: loadingState,
error,
};
const queryResponse = makeQueryResponseMemoized(graphResult, error, loadingState);
return {
datasourceInstance,
......
......@@ -11741,6 +11741,11 @@ mem@^4.0.0:
mimic-fn "^2.0.0"
p-is-promise "^2.0.0"
memoize-one@5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.1.1.tgz#047b6e3199b508eaec03504de71229b8eb1d75c0"
integrity sha512-HKeeBpWvqiVJD57ZUAsJNm71eHTykffzcLZVYWiVfQeI1rJtuEaS7hQiEpWfVVk18donPwJEcFKIkCmPJNOhHA==
"memoize-one@>=3.1.1 <6", memoize-one@^5.0.0:
version "5.0.4"
resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.0.4.tgz#005928aced5c43d890a4dfab18ca908b0ec92cbc"
......@@ -15485,10 +15490,6 @@ redux-mock-store@1.5.3:
dependencies:
lodash.isplainobject "^4.0.6"
redux-observable@1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/redux-observable/-/redux-observable-1.1.0.tgz#323a8fe53e89fdb519be2807b55f08e21c13e6f1"
redux-thunk@2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.3.0.tgz#51c2c19a185ed5187aaa9a2d08b666d0d6467622"
......
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