React 18 useDeferredValue로 검색 성능 개선하기
문제 상황
관리자 페이지의 상품 검색 기능에서 입력할 때마다 전체 목록이 리렌더링되면서 타이핑이 버벅이는 문제가 있었다. 기존에는 lodash의 debounce로 처리했는데, React 18 정식 출시 이후 useDeferredValue를 적용해봤다.
기존 방식
const [query, setQuery] = useState('');
const debouncedQuery = useMemo(
() => debounce((value) => setQuery(value), 300),
[]
);
const filteredProducts = products.filter(p =>
p.name.includes(query)
);
debounce는 잘 동작했지만, 딜레이 시간 설정이 애매했고 cleanup 처리도 신경써야 했다.
useDeferredValue 적용
const [query, setQuery] = useState('');
const deferredQuery = useDeferredValue(query);
const filteredProducts = useMemo(
() => products.filter(p => p.name.includes(deferredQuery)),
[products, deferredQuery]
);
input은 즉시 반응하고, 무거운 필터링은 낮은 우선순위로 처리된다. 별도의 타이머 관리 없이 React가 알아서 스케줄링해준다.
체감 차이
- 입력 즉시 input 값은 업데이트됨
- 리스트 렌더링은 자연스럽게 지연됨
- 빠르게 타이핑해도 끊김 없음
- Suspense와 함께 사용하면 로딩 상태도 처리 가능
디바운스보다 선언적이고, React의 동시성 렌더링과 자연스럽게 통합된다. 다만 아직 팀 전체가 React 18에 익숙하지 않아서, 코드 리뷰 때 개념 설명이 필요했다.
프로덕션 적용은 일단 이 한 곳만 했고, 더 복잡한 케이스에서도 테스트해볼 예정이다.