Poylib
기록형 프론트엔드
Poylib
전체 방문자
오늘
어제
  • 분류 전체보기 (91)
    • Programing (38)
      • Javascript (17)
      • Typescript (1)
      • React (9)
      • React-Native (6)
      • Git (4)
      • Next (1)
    • Study (36)
      • Algorithm (35)
      • Etc. (1)
    • Record (17)
      • Memoirs (12)
      • Group (5)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • Error
  • Object
  • 기초
  • javascript
  • ReactNative
  • 자바스크립트
  • typescript
  • 회고
  • 코딩테스트
  • 프로그래머스
  • Git
  • 알고리즘
  • react-native
  • vite
  • 백준
  • react
  • 코칭스터디
  • 리액트

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
Poylib

기록형 프론트엔드

[React / TypeScript] Debouncing을 활용한 검색기능 구현
Programing/React

[React / TypeScript] Debouncing을 활용한 검색기능 구현

2022. 11. 10. 19:59

디바운싱

이벤트가 연속적으로 발생할 때 마지막으로 발생한 이벤트를 기준으로 일정 시간 후에 마지막 이벤트만 실행되도록 한다. 유사한 개념으로 쓰로틀링이 있으나 검색 기능에 적용하기에 디바운싱이 더 적합한 거 같아 적용해 보았다.

디바운싱 없이 input 값을 인식하는 경우

단순히 input 태그에 들어오는 값을 받을 경우 사용자가 입력하려는 검색어가 들어올 때 매입력마다 불필요한 리랜더링이 일어난다.

const Search = () => {
  const searchHandler: React.ChangeEventHandler<HTMLInputElement> = e => {
   console.log(e.target.value);
  };

  return (
    <>
      <form onSubmit={e => e.preventDefault()}>
        <input type='text' placeholder='검색어 입력' onChange={searchHandler} />
      </form>
    </>
  )
}

이 경우에 디바운싱을 적용시켜 볼 수 있다. 예컨대 '티스토리'를 검색하고 싶다면 입력 중에는 검색 결과를 요청하지 않다가 사용자가 '티스토리'를 모두 입력했을 경우에 요청한다. 이렇게 하면 리랜더링 횟수와 서버에 검색 결과를 요청하는 통신 횟수를 줄일 수 있고 더불어 사용자가 검색 버튼을 누르지 않아도 검색 결과를 바로 받을 수 있다.

 

적용 과정

1. 디바운싱 방식으로 핸들러 만들기

 사용자가 원하는 검색 결과를 다 입력했다는 것을 알 수 있도록 타이머를 사용했다. 타이머를 만들고 매입력 마다 시간을 초기화시킨다. 더 이상 입력이 없는 경우 타이머가 끝까지 돌게 되고, 타이머가 끝나는 시점에 input창에 입력된 내용으로 검색 결과를 찾는다.

 const searchHandler: React.ChangeEventHandler<HTMLInputElement> = ({ target }) => {
    clearTimeout(timeSet.current);
    timeSet.current = setTimeout(() => {
      setSearch(target.value);
    }, 500);
    // 500ms 가 지나도록 검색창에 입력이 없다면 콜백함수가 실행된다.
  };

앞전의 예시처럼 '티스토리'를 입력하고자 하는 경우 매 입력마다 타이머가 초기화되다가 마지막 글자에서 타이머가 끝나면서 결과를 요청하는 것이다.

2. 검색 결과받아오기

타이머가 다되고 콜백이 실행됐다면 useEffect를 사용해 검색 결과를 찾도록 했다.

  useEffect(() => {
    (async () => {
      const { data } = await axios.get<SearchList[]>('http://localhost:3001/info');
      const result = data.filter(el => el.name.includes(search));
      setSearchList(result);
    })();
  }, [search]);

콜백이 들어올 때마다 검색창에 있는 내용을 포함하는 결과를 모두 보여주게 된다.

3. 검색 결과가 없는 경우

검색 결과는 통신 후 filter를 통해 값을 받기 때문에 만약 검색 결과가 없다면 빈 배열을 받게 된다. 따라서 빈 배열인 경우 결과가 없다는 문구가 나오도록 하고 이를 위해서 useEffect문에 결과가 없는 경우를 추가해주었다.

useEffect(() => {
    (async () => {
      const { data } = await axios.get<SearchList[]>('http://localhost:3001/info');
      const result = data.filter(el => el.name.includes(search));
      if (result.length) {
        setSearchList(result);
        setSearchEmpty(false);
      } else {
        setSearchList([]);
        setSearchEmpty(true);
      }
    })();
  }, [search]);

 

오류

useRef의 타입으로 NodeJS.timeout을 주는 경우에 인식하지 못하는 경우

NodeJS를 인식할 수 없어 오류처리가 되어있는데  npm으로 type/node를 설치해주면 된다.

 npm i @types/node --save

타입이 잘 설치 됐다면 오류는 해결된다.

최종 코드

import axios from 'axios';
import { useEffect, useRef, useState } from 'react';
import { SearchList } from '../interface';

const Search = () => {
  const timeSet = useRef<NodeJS.Timeout>();
  const [search, setSearch] = useState('');
  const [searchEmpty, setSearchEmpty] = useState(true);
  const [searchList, setSearchList] = useState<SearchList[]>([]);

  useEffect(() => {
    (async () => {
      const { data } = await axios.get<SearchList[]>('http://localhost:3001/info');
      const result = data.filter(el => el.name.includes(search));
      if (result.length) {
        setSearchList(result);
        setSearchEmpty(false);
      } else {
        setSearchList([]);
        setSearchEmpty(true);
      }
    })();
  }, [search]);

  const searchHandler: React.ChangeEventHandler<HTMLInputElement> = ({ target }) => {
    clearTimeout(timeSet.current);
    timeSet.current = setTimeout(() => {
      setSearch(target.value);
    }, 500);
  };

  return (
    <>
      <form onSubmit={e => e.preventDefault()}>
        <input type='text' placeholder='검색어 입력' onChange={searchHandler} />
      </form>
      {searchEmpty ? (
        <>
          <p>검색결과가 없습니다</p>
        </>
      ) : (
        <ul>
          {searchList.map(info => (
            <li key={info.id}>{info.name}</li>
          ))}
        </ul>
      )}
    </>
  );
};

export default Search;
저작자표시 비영리 변경금지 (새창열림)

'Programing > React' 카테고리의 다른 글

[React] vite 프로젝트 + vercel 배포 후 새로고침 404  (0) 2022.12.10
[React] vite 프로젝트 만들기  (0) 2022.11.03
[React] 소셜웹페이지 - 서버 통신 & 로그인  (0) 2022.08.27
[React] 댓글 입력 오류  (0) 2022.08.19
[React] 소셜웹페이지 - 자바스크립트 ➡️ 리액트 변환  (0) 2022.08.17
    'Programing/React' 카테고리의 다른 글
    • [React] vite 프로젝트 + vercel 배포 후 새로고침 404
    • [React] vite 프로젝트 만들기
    • [React] 소셜웹페이지 - 서버 통신 & 로그인
    • [React] 댓글 입력 오류
    Poylib
    Poylib
    모시깽 기록

    티스토리툴바