사용 스택 및 라이브러리: React, lodash

 

얘 좀 귀엽네 첸시? 첸세이?

 
 

Debounce 사용 목적: 검색시 input의 onChange마다 함수가 호출되는 것을 debounce를 통해 방지

 

 

1. Input의 onChange를 통한 api 호출

 
아래 함수를 살펴보자.
 

 
 
 
 
이 함수는 input에 텍스트를 입력할 경우 input의 onChange를 통해 포켓몬을 조회하는 api를 호출한다.

input의 onChange는 input에 값이 입력될 때마다 호출되기 때문에 글자 수 만큼 handleSearch 함수가 호출되는 것을 아래에서 볼 수 있다. (검색 성능 저하)


 

 
 
이를 방지하기 위해 lodashdebounce 함수를 적용해 볼 것이다.

💡Lodash란? A modern JavaScript utility library delivering modularity, performance & extras. (공식 문서에서 정의하고 있는 lodash의 의미이다; 모듈성, 성능과 추가 기능 등을 제공하는 모던 자바스크립트 유틸리티 라이브러리이다.)



2. Lodash의 debounce 적용

$ npm i -g npm //npm 설치 완료시 생략
$ npm i --save lodash


위 명령어를 통해 lodash를 설치한다.


 

Creates a debounced function that delays invoking func until after wait milliseconds have elapsed since the last time the debounced function was invoked.
 
 
 

import { debounce } from 'lodash';



필요한 함수 debounce만 구조분해로 import한다. (전체 lodash를 import하는 것보다 메모리가 훨씬 적다)
 
 

   const getPokemon = debounce(async (value: string) => {
    await axios
      .get(`https://pokeapi.co/api/v2/pokemon/${value}`)
      .then((res) => {
        setPokemon(res);
      })
      .catch((err) => {
        return;
      });
  }, 300);

 
 
 
그런 다음 기존 getPokemon 함수를 debounce 함수로 감싸준뒤 지연시간을 숫자로 적어준다. (위 예시에서는 0.3초로 설정) 
 
 
이렇게 하면 input에 타이핑이 되더라도 함수 호출을 0.3초마다 하는 것을 볼 수 있다.
 
 

 3. State 변경debounce 동시 적용

그렇다면 만약 state 변경과 debouce를 함께 호출할 경우 debounce는 효과적으로 작동할까?


아래 handleSearch 함수는 input의 onChange가 호출될 때마다(값이 변경될 때마다) 실행된다.

handleSearch내에서 setText를 통해 변하는 input값을 동시에 저장하고, debounce를 통해 api를 호출하면 아래와 같이 함수가 만들어진다.
 

const getPokemon = debounce(async (value: string) => {
    await axios
      .get(`https://pokeapi.co/api/v2/pokemon/${value}`)
      .then((res) => {
        setPokemon(res);
      })
      .catch((err) => {
        return;
      });
  }, 300);

const handleSearch = (e) => {
  setText(e.target.value);
  getPokemon(e.target.value);
}



위 함수에서 문제점은 우리의 예상과 다르게 getPokemon함수가 0.3초마다가 아닌 input의 value가 바뀔때마다 호출된다는 점이다.

이 코드의 문제점setText 함수를 실행할 때마다 컴포넌트가 재렌더링되어 debounce함수를 호출하는 getPokemon함수를 재생성한다는 점이다.
 

 4. 컴포넌트 재렌더링에 관계없이 debounce 함수 실행하기

const getPokemon = useCallback(debounce(async (value: string) => {
    await axios
      .get(`https://pokeapi.co/api/v2/pokemon/${value}`)
      .then((res) => {
        setPokemon(res);
      })
      .catch((err) => {
        return;
      });
  }, 300),
  []
;

const handleSearch = (e) => {
  setText(e.target.value);
  getPokemon(e.target.value);
}


정답은 useCallback 함수로 debounce함수를 감싸주는 것이다.

위의 getPokemon 함수는 handleSearch에서 text가 변경이 되어도 이 변수를 구독하지 않기 때문에 debounce함수를 재생성하지 않는다.



 

+ Recent posts