Have you ever built a search bar in React where every keypress triggered an update? You might have noticed your app starting to feel... sluggish.
This isn't just about visuals—constant state updates on every keystroke can slow down your UI, spike network requests, and wreck performance in real-world apps.
In this post, we’ll explore why this happens and multiple ways to fix it, including:
lodash.debounce
useEffect
+ setTimeout
Let’s start with a basic input field:
const [name, setName] = useState(''); const handleChange = (e) => { setName(e.target.value); console.log(e.target.value); };
Here’s what happens:
setName
)console.log
fires constantlyWhile fine for local inputs, this becomes a real problem when tied to API calls, filters, or expensive computations.
lodash.debounce
The most common and cleanest solution: use lodash.debounce
.
Debounce waits for a pause in user input before executing a function.
npm install lodash
import { debounce } from 'lodash'; import { useCallback, useState } from 'react'; const [name, setName] = useState(''); const debouncedSetName = useCallback( debounce((value) => { setName(value); }, 300), [] ); const handleChange = (e) => { debouncedSetName(e.target.value); };
useEffect
+ setTimeout
Don’t want to add lodash? You can achieve similar results with plain React.
const [inputValue, setInputValue] = useState(''); const [debouncedValue, setDebouncedValue] = useState(''); useEffect(() => { const handler = setTimeout(() => { setDebouncedValue(inputValue); }, 300); return () => { clearTimeout(handler); }; }, [inputValue]); const handleChange = (e) => { setInputValue(e.target.value); };
inputValue
updates immediatelysetTimeout
waits 300msdebouncedValue
updatesWhile debounce waits for a pause in typing, throttle executes at intervals no matter how fast input comes.
Use throttle if you want periodic updates (e.g., every 500ms), even during typing.
Example with lodash.throttle
:
import { throttle } from 'lodash'; const throttledChange = useCallback( throttle((val) => setName(val), 500), [] );
đź§ Use throttle when:
Use CaseRecommended ApproachBasic delay without extra libsuseEffect + setTimeout
Clean, reusable debouncelodash.debounce
Periodic updates during typinglodash.throttle
Here’s how we implemented lodash.debounce
in a real React form:
<div className="flex flex-col items-center gap-4 p-6 bg-white shadow-lg rounded-2xl w-full max-w-md mx-auto mt-10"> <input type="text" onChange={handleChange} placeholder="Enter your name" className="px-4 py-2 border border-gray-300 rounded-lg w-full focus:outline-none focus:ring-2 focus:ring-blue-400" /> <h1 className="text-xl font-semibold text-gray-800">Name: {name}</h1> </div>
Optimizing input handling in React is more than just performance—it's about building better user experiences.
Whether you use lodash
, useEffect
, or throttle
These techniques will help you scale your apps confidently and professionally.
Drop a comment or message me on Instagram @learncodepro!