Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
November 13, 2022 09:27 am GMT

Optimized React Search Bar

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

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

Gengar

Gengar

everything works fine till now,

so where's the problem

let me take you to the problem (re-rendering)

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 :

twitter

linkedIn

github


Original Link: https://dev.to/purohitdheeraj/optimized-react-search-bar-5em6

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To