mirror of
https://github.com/hyperdxio/hyperdx
synced 2026-04-21 13:37:15 +00:00
fix: Prevent crashes on Services and ClickHouse dashboards (#1535)
Closes HDX-3125 Closes HDX-3126 # Summary This PR fixes two application crashes due to infinite render loops: `useQueryState value updates --> set form values --> trigger form's useWatch/watch --> triggers useEffect --> calls setQueryState --> repeat...`. In these cases, the fix is to compare useWatch values to the previous useWatch value (using usePrevious) and only call setQueryState when the form value has changed. Before, the useEffect was also called when the query state changes.
This commit is contained in:
parent
103c63cc95
commit
4889205a86
3 changed files with 22 additions and 7 deletions
5
.changeset/many-tomatoes-arrive.md
Normal file
5
.changeset/many-tomatoes-arrive.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
"@hyperdx/app": patch
|
||||
---
|
||||
|
||||
fix: Prevent crashes on Services and ClickHouse dashboards
|
||||
|
|
@ -12,7 +12,6 @@ import { format as formatSql } from '@hyperdx/common-utils/dist/sqlFormatter';
|
|||
import { DisplayType } from '@hyperdx/common-utils/dist/types';
|
||||
import {
|
||||
Box,
|
||||
BoxComponentProps,
|
||||
Button,
|
||||
Flex,
|
||||
Grid,
|
||||
|
|
@ -38,6 +37,7 @@ import OnboardingModal from './components/OnboardingModal';
|
|||
import { useDashboardRefresh } from './hooks/useDashboardRefresh';
|
||||
import { useConnections } from './connection';
|
||||
import { parseTimeQuery, useNewTimeQuery } from './timeQuery';
|
||||
import { usePrevious } from './utils';
|
||||
|
||||
// TODO: This is a hack to set the default time range
|
||||
const defaultTimeRange = parseTimeQuery('Past 1h', false) as [Date, Date];
|
||||
|
|
@ -443,12 +443,13 @@ function ClickhousePage() {
|
|||
});
|
||||
|
||||
const watchedConnection = useWatch({ control, name: 'connection' });
|
||||
const previousWatchedConnection = usePrevious(watchedConnection);
|
||||
|
||||
useEffect(() => {
|
||||
if (watchedConnection !== connection) {
|
||||
if (previousWatchedConnection !== watchedConnection) {
|
||||
setConnection(watchedConnection ?? null);
|
||||
}
|
||||
}, [watchedConnection, connection, setConnection]);
|
||||
}, [watchedConnection, setConnection, previousWatchedConnection]);
|
||||
const DEFAULT_INTERVAL = 'Past 1h';
|
||||
const [displayedTimeInputValue, setDisplayedTimeInputValue] =
|
||||
useState(DEFAULT_INTERVAL);
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@ import { IS_LOCAL_MODE } from './config';
|
|||
import DashboardFilters from './DashboardFilters';
|
||||
import DashboardFiltersModal from './DashboardFiltersModal';
|
||||
import { HARD_LINES_LIMIT } from './HDXMultiSeriesTimeChart';
|
||||
import { usePrevious } from './utils';
|
||||
|
||||
type AppliedConfigParams = {
|
||||
source?: string | null;
|
||||
|
|
@ -1431,7 +1432,11 @@ function ServicesDashboardPage() {
|
|||
});
|
||||
|
||||
const service = useWatch({ control, name: 'service' });
|
||||
const previousService = usePrevious(service);
|
||||
|
||||
const sourceId = useWatch({ control, name: 'source' });
|
||||
const previousSourceId = usePrevious(sourceId);
|
||||
|
||||
const { data: source } = useSource({
|
||||
id: sourceId,
|
||||
});
|
||||
|
|
@ -1500,18 +1505,22 @@ function ServicesDashboardPage() {
|
|||
}, [handleSubmit, setAppliedConfigParams, onSearch, displayedTimeInputValue]);
|
||||
|
||||
// Auto-submit when source changes
|
||||
// Note: do not include appliedConfig.source in the deps,
|
||||
// to avoid infinite render loops when navigating away from the page
|
||||
useEffect(() => {
|
||||
if (sourceId && sourceId !== appliedConfig.source) {
|
||||
if (sourceId && sourceId != previousSourceId) {
|
||||
onSubmit();
|
||||
}
|
||||
}, [sourceId, appliedConfig.source, onSubmit]);
|
||||
}, [sourceId, onSubmit, previousSourceId]);
|
||||
|
||||
// Auto-submit when service changes
|
||||
// Note: do not include appliedConfig.service in the deps,
|
||||
// to avoid infinite render loops when navigating away from the page
|
||||
useEffect(() => {
|
||||
if (service !== appliedConfig.service) {
|
||||
if (service != previousService) {
|
||||
onSubmit();
|
||||
}
|
||||
}, [service, appliedConfig.service, onSubmit]);
|
||||
}, [service, onSubmit, previousService]);
|
||||
|
||||
return (
|
||||
<Box p="sm">
|
||||
|
|
|
|||
Loading…
Reference in a new issue