Recently while learning react I came across a term called debouncing ??? so what does it mean ?
let's decode it together and understand how we can use debouncing in optimizing our search/ filter component
Let's Learn , Build and Share
Learn
Debouncingπ
Debouncing refers to an optimization technique used to regulate the timeframe/interval after which a task will be executed.
for example, in search bar every state change (onChange) will cause the component re-render multiple times based on input given.
not really
goodif our component, re-renders such multiple time
Problem Statement for search component
- on every event(onChange) state gets updated and component re-renders...
- we can optimize it by providing a slight delay in state update using debouncing.
Build
talk is cheap, show me the code
Absolutely! let's deep dive into code right away, we are going to build an search bar which will filter data based on given input and display the corresponding data for it (search pokemon name and display the character accordingly)
- for build part i am going to use codesandbox
- Use React + typescript template
- follow along π
Steps to be followed
- html for view to be rendered
- setup event handlers, states(can you guess what will be our states ?)
- making an api call after render (effects)
- add debouncing (hook) to limit the state update
export default function App() {
return (
<div className="App">
<input type="text" />
<ul>
{/* here we will map our data and display */}
<li>Pokemon Name</li>
<li>
<img src="#" alt="pokemon" />
</li>
</ul>
</div>
);
}
Output so far:
states, event handlers, types (its good to start including ts in code, event small bits can be helpful to learn typescript)
import { useState } from "react";
import "./styles.css";
type Pokemon = {
name: string;
image: string;
};
export default function App() {
const [filter, setFilter] = useState<string>("");
const [pokemonData, setPokemonData] = useState<Pokemon[]>([]);
return (
<div className="App">
<input
value={filter}
type="text"
onChange={(e) => setFilter(e.target.value)}
/>
<ul>
{pokemonData.map((pokemon) => (
<li key={pokemon.name}>
<h1>{pokemon.name}</h1>
<img src={pokemon.image} alt={pokemon.name} />
</li>
))}
</ul>
</div>
);
}
- the code is pretty straight forward
- we are using
filter
state variable for storing input value (e.target.value) remember ? -
pokemonData
state variable will be used for storing an array of objects coming from api - some types are included (use TS documentation if it seems confusing)
Api Calls with Side Effects (useEffect)π₯
useEffect(() => {
// will be called after every state (filter) update
console.log("called");
const getPokemonData = async () => {
const pokemonList = await fetch(
`https://pokeapi.co/api/v2/pokemon/${filter}`
);
const pokemonListToJson = await pokemonList.json();
return {
...pokemonListToJson,
name: pokemonListToJson.name,
image: pokemonListToJson.sprites?.front_shiny
};
};
getPokemonData().then((pokemon) => setPokemonData([pokemon]));
}, [filter]);
- here comes the OG part where we are calling an api
- useEffect takes two params - (callback function, dependency array)
- so our dependency array is
[filter]
, which means on every updates done bysetFilter
, filter state variable will be updated (user input) and cause the callback function to be called inside effect - in callback function we are making an async call with async-await syntax (pretty simple to use, have a quick glance on syntax if you are not familiar with it)
- once we get data we store that object in pokemonData array with the setter function setPokemonData().
Output of view after adding useEffect hook
Gengar
everything works fine till now,
so where's the problem
let me take you to the problem (re-rendering)
its a log for query="gengar" where our side-effects were called six time causing component re-render on each change made to filter state variable
this can drastically affects the performance of our app on large-scale
Solution
Debounce
- to debounce our input we will use
useDebounce
hook - Installation :- npm i use-debounce
- if using codesandbox, add dependency from bottom left panel by typing
use-debounce
add debouncing (hook) to limit the state update
import { useEffect, useState } from "react";
import "./styles.css";
import { useDebounce } from "use-debounce";
type Pokemon = {
name: string;
image: string;
};
export default function App() {
const [filter, setFilter] = useState<string>("");
const [debouncedFilter] = useDebounce(filter, 500);
const [pokemonData, setPokemonData] = useState<Pokemon[]>([]);
useEffect(() => {
// will be called after every state (filter) update
console.log("side effect called");
const getPokemonData = async () => {
const pokemonList = await fetch(
`https://pokeapi.co/api/v2/pokemon/${filter}`
);
const pokemonListToJson = await pokemonList.json();
return {
...pokemonListToJson,
name: pokemonListToJson.name,
image: pokemonListToJson.sprites?.front_shiny
};
};
getPokemonData().then((pokemon) => setPokemonData([pokemon]));
}, [debouncedFilter]);
return (
<div className="App">
<input
value={filter}
type="text"
onChange={(e) => setFilter(e.target.value)}
/>
<ul>
{pokemonData.map((pokemon) => (
<li key={pokemon.name}>
<h1>{pokemon.name}</h1>
<img src={pokemon.image} alt={pokemon.name} />
</li>
))}
</ul>
</div>
);
}
- import useDebounce in your file
- useDebounce accepts a value and delay
- we have passed filter(search value) to
useDebounce(filter,500)
with a delay of 500ms -
debouncedFilter
state variable will store the filter value passed into debounce hook. - take your time to understand the flow , how we are passing the data into debounce hook
- and finally time to change our dependency arr, earlier our side effect was called everytime
filter
state variable is updated - now side-effect will be called when
debouncedFilter
will update on a interval of 500ms. - so we achieved some sort of optimization in our search bar
- state will be updated on every 500ms and not one every input change done by user.
Final Code Sandbox Solution
Thank you for making this far!
Today we covered a lot be it states, effects, de-bouncing, and of-course got to know about pokemon
So congratulations!π
keep learning keep building π€
You can connect with me :
Top comments (2)
so great article!!!!!β€β€β€β€β€
Glad to hear it from you
thank you π€©π€