React 18 업그레이드 후 겪은 Suspense 이슈

문제 상황

지난주 React 18이 정식 출시되어 프로젝트를 업그레이드했다. 기존 17.0.2에서 18.0.0으로 올리면서 가장 먼저 마주한 문제는 Suspense였다.

<Suspense fallback={<Spinner />}>
  <UserProfile userId={id} />
</Suspense>

기존에 잘 동작하던 코드였는데, 업그레이드 후 fallback이 깜빡이며 여러 번 렌더링되는 현상이 발생했다.

원인

React 18에서는 Concurrent Rendering이 기본으로 활성화되면서 Suspense의 동작 방식이 변경되었다. 특히 createRoot를 사용하면 자동으로 concurrent 모드가 적용된다.

기존에 사용하던 data fetching 라이브러리가 React 18의 Suspense와 완전히 호환되지 않아 발생한 문제였다. 정확히는 cache invalidation 시점에 불필요한 리렌더링이 트리거되었다.

해결

일단 급한 대로 ReactDOM.render를 유지하여 legacy 모드로 동작시켰다. 하지만 장기적으로는 SWR이나 React Query 같은 라이브러리로 전환이 필요해 보인다.

// 임시 해결
import { render } from 'react-dom';
render(<App />, document.getElementById('root'));

// 추후 마이그레이션 필요
import { createRoot } from 'react-dom/client';
const root = createRoot(document.getElementById('root'));
root.render(<App />);

다음 스프린트에서 data fetching 레이어를 전면 재검토할 예정이다. React 18의 Concurrent Feature를 제대로 활용하려면 결국 라이브러리 선택부터 다시 해야 할 것 같다.

React 18 업그레이드 후 겪은 Suspense 이슈