React 18 beta의 Automatic Batching, 실제로 얼마나 달라지나

배경

React 18 beta가 지난 6월 공개된 후 팀 내에서 도입 검토를 시작했다. concurrent rendering보다 먼저 눈에 들어온 건 automatic batching이었다.

기존에는 React 이벤트 핸들러 내부에서만 batching이 동작했다. setTimeout이나 Promise 내부의 setState는 각각 리렌더를 발생시켰다.

기존 동작 (React 17)

function handleClick() {
  fetch('/api/data').then(data => {
    setLoading(false);  // 리렌더 1
    setData(data);      // 리렌더 2
  });
}

위 코드는 2번의 리렌더가 발생했다. React DevTools Profiler로 확인하면 두 개의 commit이 기록된다.

React 18에서의 변화

function handleClick() {
  fetch('/api/data').then(data => {
    setLoading(false);
    setData(data);
    // 자동으로 batching됨, 리렌더 1회만 발생
  });
}

실제 프로젝트의 데이터 페칭 로직에 적용해봤다. 평균적으로 Promise 콜백 내 3~4개의 setState가 있었는데, 각각이 모두 batching 처리됐다.

성능 측정

대시보드 페이지의 초기 로딩 시나리오를 비교했다.

  • React 17: 12회 렌더
  • React 18: 5회 렌더

체감 성능 차이는 크지 않았지만, Profiler 상으로는 명확한 개선이 보였다.

flushSync로 opt-out

특정 상황에서 즉시 렌더링이 필요하면 flushSync를 사용할 수 있다.

import { flushSync } from 'react-dom';

flushSync(() => {
  setCount(count + 1);
});
// DOM이 즉시 업데이트됨
setFlag(true);

아직 실무에서 필요한 케이스는 없었다.

결론

코드 변경 없이 얻는 최적화라 마이그레이션 부담이 적다. concurrent features는 아직 학습 중이지만, automatic batching만으로도 18 도입을 검토할 가치가 있어 보인다.

React 18 beta의 Automatic Batching, 실제로 얼마나 달라지나