Skip to content

Commit

Permalink
fix: DH-14630: useDebouncedViewportSearch: memoization bug (#1273)
Browse files Browse the repository at this point in the history
Supports DH-14630

fixes #1272
  • Loading branch information
bmingles authored May 9, 2023
1 parent 588cb8f commit be82b14
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 7 deletions.
19 changes: 14 additions & 5 deletions packages/jsapi-components/src/useDebouncedViewportSearch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ import debounce from 'lodash.debounce';
import type { Table, TreeTable } from '@deephaven/jsapi-types';
import { TableUtils } from '@deephaven/jsapi-utils';
import { useApi } from '@deephaven/jsapi-bootstrap';
import Log from '@deephaven/log';
import { useEffect, useMemo } from 'react';
import { UseViewportDataResult } from './useViewportData';

const log = Log.module('useDebouncedViewportSearch');

export const DEBOUNCE_VIEWPORT_SEARCH_MS = 200;

/**
Expand All @@ -13,6 +16,7 @@ export const DEBOUNCE_VIEWPORT_SEARCH_MS = 200;
* @param viewportData Table viewport to filter
* @param columnName Column name to filter by
* @param debounceMs Millisecond value to debounce
* @returns A debounced search function
*/
export default function useDebouncedViewportSearch<
I,
Expand All @@ -24,34 +28,39 @@ export default function useDebouncedViewportSearch<
): (searchText: string) => void {
const dh = useApi();
const tableUtils = useMemo(() => new TableUtils(dh), [dh]);
const { table, applyFiltersAndRefresh } = viewportData;

const debouncedSearch = useMemo(
() =>
debounce((searchText: string) => {
if (viewportData.table == null) {
log.debug(`Applying debounced searchText '${searchText}'`);

if (table == null) {
return;
}

const searchTextTrimmed = searchText.trim();

if (searchTextTrimmed === '') {
viewportData.applyFiltersAndRefresh([]);
applyFiltersAndRefresh([]);
return;
}

const column = viewportData.table.findColumn(columnName);
const column = table.findColumn(columnName);
const value = tableUtils.makeFilterValue(
column.type,
searchTextTrimmed
);
const filter = [column.filter().contains(value)];

viewportData.applyFiltersAndRefresh(filter);
applyFiltersAndRefresh(filter);
}, debounceMs),
[columnName, debounceMs, tableUtils, viewportData]
[applyFiltersAndRefresh, columnName, debounceMs, table, tableUtils]
);

useEffect(
() => () => {
log.debug('Cancelling debounced search function');
debouncedSearch.cancel();
},
[debouncedSearch]
Expand Down
3 changes: 2 additions & 1 deletion packages/jsapi-components/src/useInitializeViewportData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ import useTableSize from './useTableSize';
* source table. This is intended for "human" sized tables such as those used in
* admin panels. This is not suitable for "machine" scale with millions+ rows.
* @param table The table that will be used to determine the list size.
* @returns
* @returns a React Stately ListData object. Note that this object is recreated
* by React Stately on every render.
*/
export default function useInitializeViewportData<T>(
table: Table | TreeTable | null
Expand Down
5 changes: 4 additions & 1 deletion packages/jsapi-components/src/useViewportData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,10 @@ export interface UseViewportDataResult<
* @param table
* @param viewportSize
* @param viewportPadding
* @returns An object for managing Table viewport state.
* @returns An object for managing Table viewport state. Note that the returned
* object changes on every render due to the `viewportData` not being memoized.
* This is due to the underlying React Stately `useListData` implementation that
* also changes its returned object on every render.
*/
export default function useViewportData<
TItem,
Expand Down

0 comments on commit be82b14

Please sign in to comment.