From ce1cbff4996c3c70b41761e762f9aa9837bf1840 Mon Sep 17 00:00:00 2001 From: Stephanie Freitag <stephanie.freitag@holi.team> Date: Wed, 29 Jan 2025 17:53:21 +0100 Subject: [PATCH] HOLI-10926: debounce search queries --- .../screens/search/typesense/SearchTextInput.tsx | 16 +++++----------- .../typesense/__tests__/SearchTextInput.test.tsx | 1 + 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/core/screens/search/typesense/SearchTextInput.tsx b/core/screens/search/typesense/SearchTextInput.tsx index 587a4b9ee8..71694bb325 100644 --- a/core/screens/search/typesense/SearchTextInput.tsx +++ b/core/screens/search/typesense/SearchTextInput.tsx @@ -1,6 +1,7 @@ import { CloseCircleFilled, Search } from '@holi/icons/src/generated' import { HoliIcon } from '@holi/icons/src/HoliIcon' import HoliTextInput from '@holi/ui/components/molecules/HoliTextInput' +import { useDebounce } from '@holi/ui/helper' import React, { useEffect, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import { useSearchBox } from 'react-instantsearch-core' @@ -15,7 +16,10 @@ interface SearchBoxProps { export function SearchTextInput({ initialQuery, onQueryChange, props }: SearchBoxProps) { const { t } = useTranslation() - const { query, refine } = useSearchBox(props) + // Debouncing search requests as suggested on + // https://www.algolia.com/doc/guides/building-search-ui/going-further/improve-performance/js/#debouncing + const queryHook = useDebounce((query, refine) => refine(query), 200) + const { query, refine } = useSearchBox({ ...props, queryHook }) const [inputValue, setInputValue] = useState(query) const inputRef = useRef<TextInput>(null) @@ -33,16 +37,6 @@ export function SearchTextInput({ initialQuery, onQueryChange, props }: SearchBo // eslint-disable-next-line react-hooks/exhaustive-deps }, []) - // Track when the InstantSearch query changes to synchronize it with the React state. - useEffect(() => { - // We bypass the state update if the input is focused to avoid concurrent updates when typing. - if (query !== inputValue && !inputRef.current?.isFocused()) { - setInputValue(query) - } - // We don't want to track when the React state value changes. - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [query]) - return ( <HoliTextInput aria-label={t('search.typesense.input.label')} diff --git a/core/screens/search/typesense/__tests__/SearchTextInput.test.tsx b/core/screens/search/typesense/__tests__/SearchTextInput.test.tsx index c1167e6e99..27b5c6349d 100644 --- a/core/screens/search/typesense/__tests__/SearchTextInput.test.tsx +++ b/core/screens/search/typesense/__tests__/SearchTextInput.test.tsx @@ -7,6 +7,7 @@ const mockUseSearchBox = useSearchBox as jest.MockedFunction<typeof useSearchBox jest.mock('react-instantsearch-core', () => ({ useSearchBox: jest.fn(), })) +jest.useFakeTimers() describe('SearchTextInput', () => { const mockRefine = (query = '') => { -- GitLab