React 18 RC의 Concurrent Rendering 미리 살펴보기
배경
프로젝트에서 대용량 리스트 렌더링 시 입력 필드가 버벅이는 문제가 있었다. React 18 베타가 공개되면서 Concurrent Features를 통해 이 문제를 해결할 수 있을 것 같아 테스트 환경에 적용해봤다.
startTransition 적용
검색어 입력 시 필터링되는 리스트가 3000개 이상일 때 입력 딜레이가 발생했다. startTransition으로 상태 업데이트 우선순위를 분리했다.
import { startTransition } from 'react';
function SearchList() {
const [query, setQuery] = useState('');
const [deferredQuery, setDeferredQuery] = useState('');
const handleChange = (e) => {
setQuery(e.target.value); // 즉시 반영
startTransition(() => {
setDeferredQuery(e.target.value); // 낮은 우선순위
});
};
const filteredItems = useMemo(
() => items.filter(item => item.name.includes(deferredQuery)),
[deferredQuery]
);
return (
<>
<input value={query} onChange={handleChange} />
<List items={filteredItems} />
</>
);
}
입력 필드는 즉시 반응하고, 리스트 렌더링은 뒤로 밀려나면서 UX가 개선됐다.
useDeferredValue 활용
위 패턴을 Hook으로 단순화할 수 있었다.
import { useDeferredValue } from 'react';
function SearchList() {
const [query, setQuery] = useState('');
const deferredQuery = useDeferredValue(query);
const filteredItems = useMemo(
() => items.filter(item => item.name.includes(deferredQuery)),
[deferredQuery]
);
return (
<>
<input value={query} onChange={e => setQuery(e.target.value)} />
<List items={filteredItems} />
</>
);
}
주의사항
- 아직 베타 버전이라 프로덕션 적용은 보류
- Suspense for Data Fetching은 여전히 실험 단계
- 기존 코드는 대부분 호환되지만, useEffect 타이밍이 일부 변경됨
정식 릴리스가 나오면 점진적으로 도입할 계획이다.