React 18 Beta의 Automatic Batching 적용기

배경

프로젝트에서 복잡한 폼 처리 로직이 성능 이슈를 일으키고 있었다. 여러 상태를 연속으로 업데이트할 때마다 리렌더링이 발생해 UX가 버벅이는 문제가 있었다. React 18 Beta가 공개되면서 Automatic Batching 기능이 이 문제를 해결할 수 있을 것 같아 테스트 프로젝트에 적용해봤다.

기존 문제

const handleSubmit = async () => {
  setLoading(true); // 렌더링 1
  setError(null);   // 렌더링 2
  
  const result = await api.submit(data);
  
  setData(result);  // 렌더링 3
  setLoading(false); // 렌더링 4
};

React 17에서는 이벤트 핸들러 내부의 동기 코드만 자동 배칭이 되고, Promise나 setTimeout 내부의 상태 업데이트는 각각 렌더링을 트리거했다.

React 18 Beta 적용

React 18에서는 모든 상태 업데이트가 자동으로 배칭된다. 위 코드를 그대로 사용해도 불필요한 렌더링이 줄어들었다.

// React 18에서는 자동으로 배칭됨
const result = await api.submit(data);
setData(result);
setLoading(false);
setError(null);
// 단 한 번의 렌더링만 발생

만약 즉시 렌더링이 필요한 경우 flushSync를 사용할 수 있다.

import { flushSync } from 'react-dom';

flushSync(() => {
  setCounter(c => c + 1);
});
// DOM 즉시 업데이트됨

결과

프로파일러로 측정한 결과 폼 제출 시 렌더링 횟수가 4회에서 1회로 줄었다. 체감 성능 개선도 확실했다. 다만 아직 Beta 단계라 프로덕션 적용은 보류했고, 정식 릴리즈를 기다리는 중이다.

참고

  • 기존 unstable_batchedUpdates 사용 코드는 제거 가능
  • Concurrent Features를 사용하지 않아도 Automatic Batching은 적용됨
  • 18 마이그레이션 가이드 숙지 필요
React 18 Beta의 Automatic Batching 적용기