(React) 사용자 입력에 따른 필터링 기능 구현 (+디바운싱)

개발차 DevCHA·2023년 4월 20일
2
post-thumbnail

최근 Todolist와 기능은 거의 비슷하지만 약간 다른 Sticky Wall을 만들고 있다.
Search Input에 사용자가 키워드를 입력하면 Sticky Wall에 키워드가 포함된 포스트잇만 렌더링 되도록 구현해보자.


키워드 필터링

posts.json 파일에서 전체 포스트 목록을 받아오고, 사용자가 입력한 키워드를 props로 내려받고 있다. 전체 포스트에서 키워드를 포함하는 포스트만 렌더링하고 싶다면 전체 포스트에서 제목이나 본문이 keyword를 포함하는 경우만 필터링해서 새로운 배열을 만든 뒤 렌더링해주면 된다. 코드는 아래와 같다.


import Post from './Post';
import posts from '../../helper/posts.json';

type Props = {
  keyword: string;
};

function Posts({ keyword }: Props) {
  const filteredPosts = posts.filter(
    (post) => post.title.includes(keyword) || post.content.includes(keyword)
  );

  return (
    <section>
      {filteredPosts.map((post) => (
        <Post key={post.id} post={post} />
      ))}
    </section>
  );
}

export default Posts;

하지만 이 방법으로 구현하면 키보드 입력시마다 키워드가 변경되면서 새로운 filteredPosts 배열이 생기고 화면이 리렌더링되면서 깜빡거리는 문제가 생긴다.

UX에 상당히 해롭다
문제를 해결하기 위해 디바운싱을 도입하자!


디바운싱 debouncing

디바운싱은 짧은 시간 간격으로 이벤트가 연속해서 발생하면 이벤트 핸들러를 호출하지 않다가 일정 시간이 경과한 이후에 이벤트 핸들러가 한 번만 호출되도록 하는 기술이다. 이를 통해 입력 이벤트가 발생할 때마다 즉시 처리되는 것을 방지하고, 일정 시간이 지나고 입력이 완전히 끝나면 처리하므로 성능 문제를 개선할 수 있다.

setTimeoutclearTimeout, useEffect를 이용하면 디바운싱을 구현할 수 있다.


import { useState, useEffect } from 'react';
import Post from './Post';
import posts from '../../helper/posts.json';

type Props = {
  keyword: string;
};

function Posts({ keyword }: Props) {
  const [filteredPosts, setFilteredPosts] = useState(posts);

  useEffect(() => {
    const timer = setTimeout(() => {
      setFilteredPosts(
        posts.filter((post) => post.title.includes(keyword) || post.content.includes(keyword))
      );
    }, 500);
    return () => clearTimeout(timer);
  }, [keyword]);

  return (
    <section>
      {filteredPosts.map((post) => (
        <Post key={post.id} post={post} />
      ))}
    </section>
  );
}

export default Posts;

코드 설명

  1. useEffect를 이용해 keyword가 바뀔 때마다 timer를 설정한다.
  2. useEffect의 클린업 함수 부분에 clearTimeout으로 timer를 취소한다.

이렇게 되면 컴포넌트가 마운트되었을 때 타이머가 생성되지만, 새로운 입력이 있을 경우 컴포넌트가 언마운트되면서 클린업 함수가 실행되어 기존의 타이머는 삭제된다. 그리고 useEffect 안의 setTimeout 으로 인해 사용자 입력이 0.5초 이상 멈췄을 때에만 filteredPosts가 업데이트된다.


최종 완성된 모습

훨씬 깔끔해졌다!

0개의 댓글