React 18 useTransition으로 검색 UX 개선하기

문제 상황

사내 관리자 페이지에서 5000개 이상의 상품 리스트를 필터링하는 기능을 만들었다. 검색어를 입력할 때마다 input이 버벅이는 문제가 발생했다. 사용자는 타이핑이 막히는 느낌을 받았고, debounce를 써도 근본적인 해결은 아니었다.

useTransition 적용

React 18의 useTransition을 사용해 상태 업데이트 우선순위를 조정했다.

import { useState, useTransition } from 'react';

function ProductList({ products }) {
  const [searchTerm, setSearchTerm] = useState('');
  const [filteredProducts, setFilteredProducts] = useState(products);
  const [isPending, startTransition] = useTransition();

  const handleSearch = (e) => {
    const value = e.target.value;
    setSearchTerm(value); // 즉각 반영
    
    startTransition(() => {
      // 무거운 필터링은 transition으로
      const filtered = products.filter(p => 
        p.name.toLowerCase().includes(value.toLowerCase())
      );
      setFilteredProducts(filtered);
    });
  };

  return (
    <>
      <input 
        value={searchTerm} 
        onChange={handleSearch}
        placeholder="상품 검색"
      />
      {isPending && <span>검색 중...</span>}
      <ul>
        {filteredProducts.map(product => (
          <li key={product.id}>{product.name}</li>
        ))}
      </ul>
    </>
  );
}

결과

입력 필드는 즉시 반응하고, 리스트 렌더링은 낮은 우선순위로 처리된다. 사용자는 타이핑 막힘 없이 자연스럽게 검색할 수 있게 됐다. isPending 상태로 로딩 표시도 추가했다.

debounce와 달리 딜레이가 없고, 브라우저가 알아서 우선순위를 조정해준다는 점이 장점이었다. 다만 아직 React 18 도입이 안 된 레거시 프로젝트에서는 못 쓰는 게 아쉬웠다.