React 18 Concurrent Rendering 도입 후 겪은 문제들

배경

11월에 React 18로 마이그레이션을 진행했다. Concurrent Rendering의 성능 개선을 기대했지만, 예상치 못한 문제들이 발생했다.

문제 1: Strict Mode에서 useEffect 이중 실행

React 18부터 개발 모드에서 useEffect가 의도적으로 두 번 실행된다. 외부 API 호출 로직에서 중복 요청이 발생했다.

useEffect(() => {
  let cancelled = false;
  
  fetchUserData().then(data => {
    if (!cancelled) {
      setUser(data);
    }
  });
  
  return () => {
    cancelled = true;
  };
}, []);

Cleanup 함수로 처리했지만, 팀원들에게 이 변경사항을 공유하는 것이 더 중요했다.

문제 2: 서드파티 라이브러리 호환성

일부 차트 라이브러리에서 렌더링 중단(interruption) 처리가 없어서 깨진 상태로 표시되는 문제가 있었다. useDeferredValue로 우선순위를 조정해 임시 해결했다.

const deferredData = useDeferredValue(chartData);

return <Chart data={deferredData} />;

문제 3: 상태 업데이트 배칭

자동 배칭(Automatic Batching)으로 인해 기존에 즉시 반영되던 상태 업데이트가 지연되어 UX 이슈가 발생했다. flushSync로 강제 동기화했다.

import { flushSync } from 'react-dom';

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

결론

React 18의 새로운 동작 방식을 제대로 이해하지 못한 채 적용했던 것이 문제였다. Concurrent Features는 선택적으로 도입하는 것이 안전하다는 결론을 내렸다. 당분간은 기본 기능만 사용하고, Suspense와 Transition은 내년에 검토할 예정이다.