1- import React , { useCallback , useContext , useEffect , useRef , useState } from "react" ;
1+ import React , { useContext , useEffect , useRef , useState , useTransition } from "react" ;
22import { useLocation , useNavigate } from "react-router-dom" ;
33import { styled } from "@linaria/react" ;
44import { SearchContext } from "./SearchContext" ;
@@ -60,7 +60,7 @@ export function SearchBox({
6060 const [ inputValue , setInputValue ] = useState ( search ) ;
6161 const navigate = useNavigate ( ) ;
6262 const location = useLocation ( ) ;
63- const timerRef = useRef < ReturnType < typeof setTimeout > > ( undefined ) ;
63+ const [ , startTransition ] = useTransition ( ) ;
6464 const ownNavigateRef = useRef ( false ) ;
6565
6666 // Sync from URL (back/forward navigation, clicking links)
@@ -70,37 +70,27 @@ export function SearchBox({
7070 return ;
7171 }
7272 const urlSearch = new URLSearchParams ( location . search ) . get ( "search" ) ?? "" ;
73- setSearch ( urlSearch ) ;
7473 setInputValue ( urlSearch ) ;
75- clearTimeout ( timerRef . current ) ;
74+ startTransition ( ( ) => setSearch ( urlSearch ) ) ;
7675 // Intentionally depends only on location.search — we sync *from* the URL.
7776 // search/setSearch are omitted because including them would create an
7877 // infinite loop: setSearch triggers a navigate which changes location.search.
7978 } , [ location . search ] ) ; // eslint-disable-line react-hooks/exhaustive-deps
8079
81- // Cleanup debounce timer on unmount
82- useEffect ( ( ) => ( ) => clearTimeout ( timerRef . current ) , [ ] ) ;
83-
84- const onChange = useCallback < React . ChangeEventHandler < HTMLInputElement > > (
85- ( { target : { value } } ) => {
86- setInputValue ( value ) ;
87- clearTimeout ( timerRef . current ) ;
88- timerRef . current = setTimeout ( ( ) => {
89- const wasSearching = search !== "" ;
90- setSearch ( value ) ;
91- ownNavigateRef . current = true ;
92- // Push a history entry when starting a new search so back button works.
93- // Replace while typing to avoid polluting history with every keystroke.
94- const replace = wasSearching || value === "" ;
95- if ( value === "" ) {
96- navigate ( baseUrl , { replace } ) ;
97- } else {
98- navigate ( `${ baseUrl } ?search=${ encodeURIComponent ( value ) } ` , { replace } ) ;
99- }
100- } , 150 ) ;
101- } ,
102- [ search , setSearch , navigate , baseUrl ] ,
103- ) ;
80+ const onChange : React . ChangeEventHandler < HTMLInputElement > = ( { target : { value } } ) => {
81+ const wasSearching = inputValue !== "" ;
82+ setInputValue ( value ) ;
83+ ownNavigateRef . current = true ;
84+ // Push a history entry when starting a new search so back button works.
85+ // Replace while typing to avoid polluting history with every keystroke.
86+ const replace = wasSearching || value === "" ;
87+ startTransition ( ( ) => {
88+ setSearch ( value ) ;
89+ navigate ( value === "" ? baseUrl : `${ baseUrl } ?search=${ encodeURIComponent ( value ) } ` , {
90+ replace,
91+ } ) ;
92+ } ) ;
93+ } ;
10494
10595 const ref = useCtrlFHook < HTMLInputElement > ( ) ;
10696
0 commit comments