React 18 Concurrent Rendering 적용 후기
배경
3월에 React 18이 정식 출시된 후 미뤄왔던 업그레이드를 진행했다. 특히 검색 페이지의 성능 문제가 있어서 Concurrent Features를 적용해보기로 했다.
기존 문제는 검색어 입력 시 매 타이핑마다 무거운 필터링 로직이 실행되면서 입력이 버벅이는 현상이었다.
useTransition 적용
import { useState, useTransition } from 'react';
function SearchPage() {
const [query, setQuery] = useState('');
const [isPending, startTransition] = useTransition();
const [searchResults, setSearchResults] = useState([]);
const handleChange = (e) => {
const value = e.target.value;
setQuery(value); // 즉시 반영
startTransition(() => {
// 무거운 검색 로직은 낮은 우선순위로
const results = expensiveFilterFunction(value);
setSearchResults(results);
});
};
return (
<>
<input value={query} onChange={handleChange} />
{isPending && <Spinner />}
<ResultList items={searchResults} />
</>
);
}
입력 필드는 즉시 반응하고, 결과 목록 업데이트는 지연시켰다. 체감 성능이 확실히 개선됐다.
주의사항
createRoot로 마이그레이션 필요 (기존ReactDOM.render는 legacy 모드)- Suspense 경계 설정이 중요함
- 모든 상태 업데이트를 transition으로 감쌀 필요는 없음
결과
사용자 입력 반응성이 눈에 띄게 좋아졌다. 다만 팀원들에게 useTransition 사용 시점을 설명하는 게 생각보다 어려웠다. "느린 업데이트"의 기준이 애매해서 케이스별로 판단이 필요했다.
다음은 Suspense를 활용한 데이터 fetching 패턴을 실험해볼 예정이다.