React 18 Concurrent Rendering 도입 후기
배경
회사 어드민 프로젝트가 React 17.0.2를 사용 중이었는데, 데이터 테이블 렌더링 시 간헐적인 버벅임이 있었다. React 18의 Concurrent Features가 도움이 될 것 같아 업그레이드를 진행했다.
마이그레이션 과정
1. createRoot 전환
기존 ReactDOM.render를 createRoot로 변경했다.
// Before
import ReactDOM from 'react-dom';
ReactDOM.render(<App />, document.getElementById('root'));
// After
import { createRoot } from 'react-dom/client';
const root = createRoot(document.getElementById('root'));
root.render(<App />);
2. Automatic Batching 확인
이전에는 setTimeout 내부의 setState가 배칭되지 않아 렌더링이 두 번 발생했다. React 18에서는 자동으로 배칭된다.
const handleClick = () => {
setTimeout(() => {
setCount(c => c + 1);
setFlag(f => !f);
// React 17: 2번 렌더
// React 18: 1번 렌더
}, 1000);
};
3. useTransition 적용
필터링 로직에 useTransition을 적용해 입력 반응성을 개선했다.
const [isPending, startTransition] = useTransition();
const [filter, setFilter] = useState('');
const handleFilterChange = (e) => {
startTransition(() => {
setFilter(e.target.value);
});
};
입력 필드는 즉시 반응하고, 무거운 리스트 렌더링은 지연되어 UX가 확실히 나아졌다.
이슈
- React Testing Library 일부 테스트에서 act warning 발생. @testing-library/react를 13.3으로 업데이트해서 해결
- Styled-components 5.3.5에서 hydration mismatch 경고. 아직 조사 중
결론
Breaking Change가 거의 없어서 반나절 만에 마이그레이션을 완료했다. Automatic Batching만으로도 불필요한 렌더링이 줄었고, useTransition은 특정 케이스에서 확실히 효과적이었다. Server Components는 아직 Next.js 12에서 알파 단계라 보류했다.