From e6db01dcbe9e14bf8de87caf0ef951166c0622bd Mon Sep 17 00:00:00 2001 From: Andrej Ocenas Date: Mon, 15 May 2023 14:24:54 +0200 Subject: [PATCH] FlameGraph: Debounce search update preventing too frequent rerenders (#68405) --- .../components/FlameGraphHeader.tsx | 39 +++++++++++++++++-- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/public/app/plugins/panel/flamegraph/components/FlameGraphHeader.tsx b/public/app/plugins/panel/flamegraph/components/FlameGraphHeader.tsx index 8b062c10bef..46d7803a794 100644 --- a/public/app/plugins/panel/flamegraph/components/FlameGraphHeader.tsx +++ b/public/app/plugins/panel/flamegraph/components/FlameGraphHeader.tsx @@ -1,5 +1,7 @@ import { css } from '@emotion/css'; -import React from 'react'; +import React, { useEffect, useState } from 'react'; +import useDebounce from 'react-use/lib/useDebounce'; +import usePrevious from 'react-use/lib/usePrevious'; import { GrafanaTheme2, CoreApp } from '@grafana/data'; import { Button, Input, RadioButtonGroup, useStyles2 } from '@grafana/ui'; @@ -53,17 +55,21 @@ const FlameGraphHeader = ({ setSelectedBarIndex(0); setRangeMin(0); setRangeMax(1); + // We could set only one and wait them to sync but there is no need to debounce this. setSearch(''); + setLocalSearch(''); }; + const [localSearch, setLocalSearch] = useSearchInput(search, setSearch); + return (
{ - setSearch(v.currentTarget.value); + setLocalSearch(v.currentTarget.value); }} placeholder={'Search..'} width={44} @@ -87,6 +93,33 @@ const FlameGraphHeader = ({ ); }; +function useSearchInput( + search: string, + setSearch: (search: string) => void +): [string | undefined, (search: string) => void] { + const [localSearchState, setLocalSearchState] = useState(search); + const prevSearch = usePrevious(search); + + // Debouncing cause changing parent search triggers rerender on both the flamegraph and table + useDebounce( + () => { + setSearch(localSearchState); + }, + 250, + [localSearchState] + ); + + // Make sure we still handle updates from parent (from clicking on a table item for example). We check if the parent + // search value changed to something that isn't our local value. + useEffect(() => { + if (prevSearch !== search && search !== localSearchState) { + setLocalSearchState(search); + } + }, [search, prevSearch, localSearchState]); + + return [localSearchState, setLocalSearchState]; +} + const getStyles = (theme: GrafanaTheme2, app: CoreApp) => ({ header: css` display: flow-root;