React 18의 Automatic Batching과 성능 개선
배경
3월 말 React 18이 정식 릴리즈되어 회사 프로젝트에 적용해봤다. 가장 눈에 띄는 변화는 Automatic Batching이었다.
기존 문제
React 17까지는 이벤트 핸들러 내부에서만 batching이 동작했다. setTimeout이나 Promise 내부의 상태 업데이트는 각각 리렌더링을 발생시켰다.
// React 17: 2번 렌더링
fetch('/api/user').then(data => {
setUser(data.user); // 렌더링 1
setLoading(false); // 렌더링 2
});
이를 해결하려고 unstable_batchedUpdates를 사용했는데, 이름부터 불안정해 보였다.
React 18의 변화
React 18에서는 모든 상황에서 자동으로 batching이 적용된다.
// React 18: 1번 렌더링
fetch('/api/user').then(data => {
setUser(data.user);
setLoading(false);
// 자동으로 batching됨
});
실제 대시보드 페이지에서 여러 API를 호출하는 부분에 적용했더니 불필요한 리렌더링이 현저히 줄어들었다.
주의사항
만약 의도적으로 동기적 업데이트가 필요하다면 flushSync를 사용할 수 있다.
import { flushSync } from 'react-dom';
flushSync(() => {
setCounter(c => c + 1);
});
// 즉시 렌더링됨
마이그레이션
업그레이드는 생각보다 순조로웠다. ReactDOM.render를 createRoot로 변경하는 정도였고, 기존 코드는 대부분 그대로 동작했다.
// Before
ReactDOM.render(<App />, document.getElementById('root'));
// After
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
Concurrent Features는 아직 안정화될 때까지 기다려볼 예정이다.