I'm currently working on a React project that utilizes React Router with react-router-dom. In one of my components, I'm using the setSearchParams function from useSearchParams to manage and modify URL query parameters. According to my understanding, when I use setSearchParams to update the URL query parameters and return the current object reference, it should not trigger the useEffect. However, I've noticed that the useEffect is triggered even when I return the same object reference.
Why does it happen?
I have an input field that triggers an useEffect whenever the user types. While I want the input to be responsive, I also want to avoid triggering the useEffect too frequently, especially when the user is typing rapidly.
How can I accomplish that?
Here's my code:
import {
BrowserRouter as Router,
Route,
Routes,
useSearchParams,
} from 'react-router-dom';
import React, { useEffect, useRef } from 'react';
import './style.css';
const Home = () => {
const debounce = useDebounce();
const [searchParams, setSearchParams] = useSearchParams();
const name = searchParams.get('name') || '';
useEffect(() => {
console.log('useEffect triggered');
// i am gonna call an API here
}, [searchParams]);
return (
<div>
<div>
<label>Name:</label>
<input
type="text"
value={name}
onChange={(e) => {
setSearchParams(
(prev) => {
prev.set('name', e.target.value);
return prev;
},
{ replace: true }
);
}}
/>
</div>
</div>
);
};
function useDebounce() {
const timeout = useRef(null);
function debounce(cb, delay = 1000) {
return (...args) => {
if (timeout.current) clearTimeout(timeout.current);
timeout.current = setTimeout(() => {
cb(...args);
}, delay);
};
}
return debounce;
}
function App() {
return (
<Router>
<div>
<nav>
<ul>
<li>
<a href="/">Home</a>
</li>
</ul>
</nav>
<Routes>
<Route path="/" element={<Home />} />
</Routes>
</div>
</Router>
);
}
export default App;
I think conceptually your understanding is "correct", but the current implementation of
useSearchParamsdoesn't return a stablesearchParamsobject reference. There is an open GitHub issue here regarding "Make setSearchParams stable".Some workarounds are suggested in the thread.
What this means is that using
searchParamsas auseEffecthook dependency will trigger the effect each render cycle.You can't debounce React hooks. You should debounce the function that would be called too often as a side-effect.
Example debouncing a function that calls the API.