From 538ea1127ebdfdb02ee043d50f3887db32260bfb Mon Sep 17 00:00:00 2001 From: David Kaltschmidt Date: Tue, 2 Oct 2018 11:19:07 +0200 Subject: [PATCH] Perf on query field and typeahead - Lower debounce - refactor suggestion selection - make Portal pure - use prev suggestions object if suggestions are the same --- .../app/features/explore/PromQueryField.tsx | 1 + public/app/features/explore/QueryField.tsx | 54 ++++++++++--------- public/app/features/explore/Typeahead.tsx | 4 +- 3 files changed, 34 insertions(+), 25 deletions(-) diff --git a/public/app/features/explore/PromQueryField.tsx b/public/app/features/explore/PromQueryField.tsx index 293688276dc..479529d8e68 100644 --- a/public/app/features/explore/PromQueryField.tsx +++ b/public/app/features/explore/PromQueryField.tsx @@ -575,6 +575,7 @@ class PromQueryField extends React.Component {error ?
{error}
: null} diff --git a/public/app/features/explore/QueryField.tsx b/public/app/features/explore/QueryField.tsx index 13364729e7e..93969d214e4 100644 --- a/public/app/features/explore/QueryField.tsx +++ b/public/app/features/explore/QueryField.tsx @@ -11,10 +11,17 @@ import NewlinePlugin from './slate-plugins/newline'; import Typeahead from './Typeahead'; import { makeFragment, makeValue } from './Value'; -export const TYPEAHEAD_DEBOUNCE = 300; +export const TYPEAHEAD_DEBOUNCE = 100; -function flattenSuggestions(s: any[]): any[] { - return s ? s.reduce((acc, g) => acc.concat(g.items), []) : []; +function getSuggestionByIndex(suggestions: SuggestionGroup[], index: number): Suggestion { + // Flatten suggestion groups + const flattenedSuggestions = suggestions.reduce((acc, g) => acc.concat(g.items), []); + const correctedIndex = Math.max(index, 0) % flattenedSuggestions.length; + return flattenedSuggestions[correctedIndex]; +} + +function hasSuggestions(suggestions: SuggestionGroup[]): boolean { + return suggestions && suggestions.length > 0; } export interface Suggestion { @@ -154,8 +161,14 @@ class QueryField extends React.Component { if (group.items) { if (prefix) { @@ -241,6 +254,11 @@ class QueryField extends React.Component group.items && group.items.length > 0); // Filter out empty groups + // Keep same object for equality checking later + if (_.isEqual(filteredSuggestions, this.state.suggestions)) { + filteredSuggestions = this.state.suggestions; + } + this.setState( { suggestions: filteredSuggestions, @@ -326,12 +344,7 @@ class QueryField extends React.Component 0; - if (!hasSuggesstions) { + if (!hasSuggestions(suggestions)) { menu.removeAttribute('style'); return; } @@ -436,18 +448,12 @@ class QueryField extends React.Component { const { portalPrefix } = this.props; - const { suggestions } = this.state; - const hasSuggesstions = suggestions && suggestions.length > 0; - if (!hasSuggesstions) { + const { suggestions, typeaheadIndex } = this.state; + if (!hasSuggestions(suggestions)) { return null; } - // Guard selectedIndex to be within the length of the suggestions - let selectedIndex = Math.max(this.state.typeaheadIndex, 0); - const flattenedSuggestions = flattenSuggestions(suggestions); - selectedIndex = selectedIndex % flattenedSuggestions.length || 0; - const selectedItem: Suggestion | null = - flattenedSuggestions.length > 0 ? flattenedSuggestions[selectedIndex] : null; + const selectedItem = getSuggestionByIndex(suggestions, typeaheadIndex); // Create typeahead in DOM root so we can later position it absolutely return ( @@ -482,7 +488,7 @@ class QueryField extends React.Component { +class Portal extends React.PureComponent<{ index?: number; prefix: string }, {}> { node: HTMLElement; constructor(props) { diff --git a/public/app/features/explore/Typeahead.tsx b/public/app/features/explore/Typeahead.tsx index 9924488035c..999e5003eaf 100644 --- a/public/app/features/explore/Typeahead.tsx +++ b/public/app/features/explore/Typeahead.tsx @@ -23,7 +23,9 @@ class TypeaheadItem extends React.PureComponent { componentDidUpdate(prevProps) { if (this.props.isSelected && !prevProps.isSelected) { - scrollIntoView(this.el); + requestAnimationFrame(() => { + scrollIntoView(this.el); + }); } }