Optimized React Search Bar 🔯
Tags: react, debounce, render, javascript
Published: 2022-11-13 09:27:56

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 ~~good~~ if 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 

```js
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:

![Output of basic html view](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4li6rzctrlc6xb63t1ur.PNG)

## states, event handlers, types (its good to start including ts in code, event small bits can be helpful to learn typescript)

```js
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)🔥
```js
  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 by `setFilter` , 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

Chimchar
![Chimchar](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mpns9urz9qy3umzi0fgd.PNG)

Gengar

![Gengar](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qibg3h78keyvty6szfzb.PNG)

everything works fine till now,
so where's the problem
---
> let me take you to the problem (re-rendering)

![re-rendering](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/stdrtb41rnw6w994mxwu.PNG)

- 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 

```js
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

{% embed https://xvi2tj.csb.app/ %}



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 :

|Twitter | LinkedIn | Github |
|--------|----------|--------|
|[![Twitter](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2tt83iv246d7jgw6x6lx.png)](https://twitter.com/the_indianyoga)|[![LinkedIn](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2fi24wqrddse1e7u8vru.png)](https://www.linkedin.com/in/dheeraj-purohit-79ba4a168/)|[![github](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v12byympkhsho8i5akpp.png)](https://github.com/purohitdheeraj)|