Skip to content

Commit

Permalink
memoize editor frame (#89865)
Browse files Browse the repository at this point in the history
  • Loading branch information
flash1293 authored Feb 4, 2021
1 parent caf9d83 commit 1818dd7
Showing 1 changed file with 117 additions and 46 deletions.
163 changes: 117 additions & 46 deletions x-pack/plugins/lens/public/app_plugin/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@
import './app.scss';

import _ from 'lodash';
import React, { useState, useEffect, useCallback } from 'react';
import React, { useState, useEffect, useCallback, useRef } from 'react';
import { i18n } from '@kbn/i18n';
import { NotificationsStart } from 'kibana/public';
import { NotificationsStart, Toast } from 'kibana/public';
import { VisualizeFieldContext } from 'src/plugins/ui_actions/public';
import { Datatable } from 'src/plugins/expressions/public';
import { EuiBreadcrumb } from '@elastic/eui';
import { downloadMultipleAs } from '../../../../../src/plugins/share/public';
import {
Expand All @@ -26,21 +28,27 @@ import { injectFilterReferences } from '../persistence';
import { NativeRenderer } from '../native_renderer';
import { trackUiEvent } from '../lens_ui_telemetry';
import {
DataPublicPluginStart,
esFilters,
exporters,
Filter,
IndexPattern as IndexPatternInstance,
IndexPatternsContract,
Query,
SavedQuery,
syncQueryStateWithUrl,
} from '../../../../../src/plugins/data/public';
import { LENS_EMBEDDABLE_TYPE, getFullPath } from '../../common';
import { LensAppProps, LensAppServices, LensAppState } from './types';
import { getLensTopNavConfig } from './lens_top_nav';
import { Document } from '../persistence';
import { SaveModal } from './save_modal';
import {
LensByReferenceInput,
LensEmbeddableInput,
} from '../editor_frame_service/embeddable/embeddable';
import { useTimeRange } from './time_range';
import { EditorFrameInstance } from '../types';

export function App({
history,
Expand Down Expand Up @@ -515,6 +523,12 @@ export function App({
}
};

const lastKnownDocRef = useRef(state.lastKnownDoc);
lastKnownDocRef.current = state.lastKnownDoc;

const activeDataRef = useRef(state.activeData);
activeDataRef.current = state.activeData;

const { TopNavMenu } = navigation.ui;

const savingPermitted = Boolean(state.isSaveable && application.capabilities.visualize.save);
Expand Down Expand Up @@ -660,50 +674,24 @@ export function App({
/>
</div>
{(!state.isLoading || state.persistedDoc) && (
<NativeRenderer
className="lnsApp__frame"
render={editorFrame.mount}
nativeProps={{
searchSessionId: state.searchSessionId,
dateRange: resolvedDateRange,
query: state.query,
filters: state.filters,
savedQuery: state.savedQuery,
doc: state.persistedDoc,
onError,
showNoDataPopover,
initialContext,
onChange: ({ filterableIndexPatterns, doc, isSaveable, activeData }) => {
if (isSaveable !== state.isSaveable) {
setState((s) => ({ ...s, isSaveable }));
}
if (!_.isEqual(state.persistedDoc, doc) && !_.isEqual(state.lastKnownDoc, doc)) {
setState((s) => ({ ...s, lastKnownDoc: doc }));
}
if (!_.isEqual(state.activeData, activeData)) {
setState((s) => ({ ...s, activeData }));
}

// Update the cached index patterns if the user made a change to any of them
if (
state.indexPatternsForTopNav.length !== filterableIndexPatterns.length ||
filterableIndexPatterns.some(
(id) =>
!state.indexPatternsForTopNav.find((indexPattern) => indexPattern.id === id)
)
) {
getAllIndexPatterns(
filterableIndexPatterns,
data.indexPatterns,
notifications
).then((indexPatterns) => {
if (indexPatterns) {
setState((s) => ({ ...s, indexPatternsForTopNav: indexPatterns }));
}
});
}
},
}}
<MemoizedEditorFrameWrapper
editorFrame={editorFrame}
resolvedDateRange={resolvedDateRange}
onError={onError}
showNoDataPopover={showNoDataPopover}
initialContext={initialContext}
setState={setState}
data={data}
notifications={notifications}
query={state.query}
filters={state.filters}
searchSessionId={state.searchSessionId}
isSaveable={state.isSaveable}
savedQuery={state.savedQuery}
persistedDoc={state.persistedDoc}
indexPatterns={state.indexPatternsForTopNav}
activeData={activeDataRef}
lastKnownDoc={lastKnownDocRef}
/>
)}
</div>
Expand Down Expand Up @@ -732,6 +720,89 @@ export function App({
);
}

const MemoizedEditorFrameWrapper = React.memo(function EditorFrameWrapper({
editorFrame,
query,
filters,
searchSessionId,
isSaveable: oldIsSaveable,
savedQuery,
persistedDoc,
indexPatterns: indexPatternsForTopNav,
resolvedDateRange,
onError,
showNoDataPopover,
initialContext,
setState,
data,
notifications,
lastKnownDoc,
activeData: activeDataRef,
}: {
editorFrame: EditorFrameInstance;
searchSessionId: string;
query: Query;
filters: Filter[];
isSaveable: boolean;
savedQuery?: SavedQuery;
persistedDoc?: Document | undefined;
indexPatterns: IndexPatternInstance[];
resolvedDateRange: { fromDate: string; toDate: string };
onError: (e: { message: string }) => Toast;
showNoDataPopover: () => void;
initialContext: VisualizeFieldContext | undefined;
setState: React.Dispatch<React.SetStateAction<LensAppState>>;
data: DataPublicPluginStart;
notifications: NotificationsStart;
lastKnownDoc: React.MutableRefObject<Document | undefined>;
activeData: React.MutableRefObject<Record<string, Datatable> | undefined>;
}) {
return (
<NativeRenderer
className="lnsApp__frame"
render={editorFrame.mount}
nativeProps={{
searchSessionId,
dateRange: resolvedDateRange,
query,
filters,
savedQuery,
doc: persistedDoc,
onError,
showNoDataPopover,
initialContext,
onChange: ({ filterableIndexPatterns, doc, isSaveable, activeData }) => {
if (isSaveable !== oldIsSaveable) {
setState((s) => ({ ...s, isSaveable }));
}
if (!_.isEqual(persistedDoc, doc) && !_.isEqual(lastKnownDoc.current, doc)) {
setState((s) => ({ ...s, lastKnownDoc: doc }));
}
if (!_.isEqual(activeDataRef.current, activeData)) {
setState((s) => ({ ...s, activeData }));
}

// Update the cached index patterns if the user made a change to any of them
if (
indexPatternsForTopNav.length !== filterableIndexPatterns.length ||
filterableIndexPatterns.some(
(id) => !indexPatternsForTopNav.find((indexPattern) => indexPattern.id === id)
)
) {
getAllIndexPatterns(filterableIndexPatterns, data.indexPatterns, notifications).then(
(indexPatterns) => {
if (indexPatterns) {
setState((s) => ({ ...s, indexPatternsForTopNav: indexPatterns }));
}
}
);
}
},
}}
/>
);
});

export async function getAllIndexPatterns(
ids: string[],
indexPatternsService: IndexPatternsContract,
Expand Down

0 comments on commit 1818dd7

Please sign in to comment.