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