React বর্তমানে বহুল জনপ্রিয় একটি জাভাস্কিপ্ট লাইব্রেরি, যার শুরু হয়েছিল ফেসবুকের একটি ওপেন সোর্স প্রজেক্টের মাধ্যমে। React এর ১৬.৮ ভার্শনে নিয়ে আসা হয়েছে React Hook এর মত ফিচার যার মাধ্যমে খুব সহজেই আমরা React স্টেট এবং অপর ফিচারগুলো সুবিধা পেতে পারি যার জন্য React ক্লাস ডিক্লেয়ার করার প্রয়োজন নেই। এভাবে React এর মাধ্যমে আগের চেয়ে ক্লিন কোড করা সম্ভব হচ্ছে।

আমরা  আমাদের তৈরিকৃত ওয়েভ এপ্লিকেশনে মাঝে মধ্যেই এমন কিছু চাই যে ইউজার কোন সার্চ ফিল্ডে টাইপ করবে এবং সার্চ করা রেজাল্ট সাথে সাথেই কোথাও দেখা যাবে। এইখানে গুরুত্বপূর্ণ বিষয় এই যে আমরা যখন সার্চ করছি তখন প্রতি key press এ যদি ব্যাকএন্ডে সার্চ রেজাল্ট রিকুয়েস্ট যায় বা ফ্রন্টএন্ডের সার্চ আইটেমগুলাতে সার্চ রিকুয়েস্ট করা হয় তাতে অনেক অগুরুত্বপূর্ণ রিকুয়েস্ট করা হয় এবং এমন কিছু সার্চ রেজাল্ট populate করা হয় যা দরকারি ছিল না। এসব অদরকারি রিকুয়েস্ট না করার জন্য Debounce Function ব্যবহার করা হয় সচরাচর। Debounce Function এর কাজ হয় key stroke বন্ধ না হওয়া পর্যন্ত সার্চ রেজাল্ট populate করার জন্য ব্যাকেএন্ড সার্চ রিকুয়েস্ট বা ফ্রন্টএন্ড সার্চ রিকুয়েস্ট না করা ।

demo screenshot

Source: [1]

অটো সার্চের জন্য আমরা রিয়েক্ট হুকের useEffect এবং useState এর সাহায্য নিয়ে আমাদের জন্য একটি কাস্টম হুক useDebounce তৈরি করব যার কাজ হবে আমাদের আগে থেকে ঠিক করে রাখা সময়ের মধ্যে কোন key stroke না হলে আমাদের সার্চ ফাংশন ফায়ার করা। এইখানে useEffect আর useState কিভাবে ব্যাবহার করা হবে তাই এই ব্যাপারে ভাল ধারণা থাকা আবশ্যক । এর জন্য official doc অবশ্যই আগে পড়া থাকা ভাল ।

প্রথমে আমরা আমাদের কাজের সুবিধার জন্য একটি Custom React Hook তৈরি করব যা আমাদের Debounce এর কাজ করে দিবে । যেহেতু এইটা আমাদের custom hook তাই এর নামের শুরুতে use ব্যাবহার করব, এইটা custom hook করার convention।

import React, { useState, useEffect } from 'react';

export function useDebounce(value, delay) {
    // State and setters for debounced value
  const [debouncedValue, setDebouncedValue] = useState(value);

  useEffect(
    () => {
      // Set debouncedValue to value (passed in) after the specified delay
      const handler = setTimeout(() => {
        setDebouncedValue(value);
      }, delay);

      // Return a cleanup function that will be called every time ...
      // ... useEffect is re-called. useEffect will only be re-called ...
      // ... if value changes (see the inputs array below). 
      // This is how we prevent debouncedValue from changing if value is ...
      // ... changed within the delay period. Timeout gets cleared and restarted.
      // To put it in context, if the user is typing within our app's ...
      // ... search box, we don't want the debouncedValue to update until ...
      // ... they've stopped typing for more than 500ms.
      return () => {
        clearTimeout(handler);
      };
    },
    // Only re-call effect if value changes
    // You could also add the "delay" var to inputs array if you ...
    // ... need to be able to change that dynamically.
    [value] 
  );
  return debouncedValue;
}

Source[1]

কোডের পরের পার্টে আমরা আমাদের সার্চ বারটি করব যেখান থেকে আমরা আমাদের custom hook আর সার্চ ফাংশনকে কল করব এবং সার্চ রেজাল্ট দেখাবো।

import React, { useState, useEffect } from 'react';
import useDebounce from './useDebounce';
import searchCharacters from './searchCharacters';


function SearchBar = () => { 

  // State and setter for search term
  const [searchTerm, setSearchTerm] = useState('');
  // State and setter for search results
  const [results, setResults] = useState([]);
  // State for search status (whether there is a pending API request)
  const [isSearching, setIsSearching] = useState(false);
  
  // Now we call our hook, passing in the current searchTerm value.
  // The hook will only return the latest value (what we passed in) ...
  // ... if it's been more than 500ms since it was last called.
  // Otherwise, it will return the previous value of searchTerm.
  // The goal is to only have the API call fire when user stops typing ...
  // ... so that we aren't hitting our API rapidly.
  const debouncedSearchTerm = useDebounce(searchTerm, 500);

  // Here's where the API call happens
  // We use useEffect since this is an asynchronous action
  useEffect(
    () => {
      // Make sure we have a value (user has entered something in input)
      if (debouncedSearchTerm) {
        // Set isSearching state
        setIsSearching(true);
        // Fire off our API call
        searchCharacters(debouncedSearchTerm).then(results => {
          // Set back to false since request finished
          setIsSearching(false);
          // Set results state
          setResults(results);
        });
      } else {
        setResults([]);
      }
    },
    // This is the useEffect input array
    // Our useEffect function will only execute if this value changes ...
    // ... and thanks to our hook it will only change if the original ...
    // value (searchTerm) hasn't changed for more than 500ms.
    [debouncedSearchTerm]
  );
  
  // Pretty standard UI with search input and results
  return (
    <div>
      <input
        placeholder="Search Marvel Comics"
        onChange={e => setSearchTerm(e.target.value)}
      />

      {isSearching && <div>Searching ...</div>}

      {results.map(result => (
        <div key={result.id}>
          <h4>{result.title}</h4>
          <img
            src={`${result.thumbnail.path}/portrait_incredible.${
              result.thumbnail.extension
            }`}
          />
        </div>
      ))}
    </div>
  );

  

}




Source[1]

ফাইনালি আমাদের সার্চ ফাংশনটির কাজ করব যা Marvel Comic API থেকে আমাদের ফেভারিট ক্যারেক্টার খুঁজে আনবে। কীভাবে নতুন Api Key পাবো তা মারভেল কমিক Api Documentation থেকে আমরা জানতে পারবো।

// API search function
import React, { useState, useEffect } from 'react';

export function searchCharacters(search) {
  const apiKey = 'f9dfb1e8d466d36c27850bedd2047687';
  const queryString `apikey=${apiKey}&titleStartsWith=${search}`;
  return fetch(
    `https://gateway.marvel.com/v1/public/comics?${queryString}`,
    {
      method: 'GET'
    }
  )
    .then(r => r.json())
    .then(r => r.data.results)
    .catch(error => {
      console.error(error);
      return [];
    });
}

Source[1]

Debounce Hook এর মাধ্যমে আমরা যে কোন ভ্যালুকে Debounce করে আমরা component এ ব্যবহার করতে পারি। এর মাধ্যমে অদরকারি রিকুয়েস্ট করা হবে না। এই ট্রিকটা আমরা চাইলে সার্চের অটো ফিল আপ সাজেশনও ব্যবহার করতে পারি।  

Reference:
1: https://dev.to/gabe_ragland/debouncing-with-react-hooks-jci