React 18 업그레이드 후 Suspense 동작 변화
문제 상황
지난주 팀 프로젝트를 React 17에서 18로 업그레이드했다. 대부분의 기능은 정상 작동했지만, 코드 스플리팅된 페이지 로딩 시 Suspense fallback이 깜빡이는 현상이 발생했다.
기존 코드는 다음과 같았다:
const Dashboard = lazy(() => import('./Dashboard'));
function App() {
return (
<Suspense fallback={<Spinner />}>
<Dashboard />
</Suspense>
);
}
원인
React 18에서는 Suspense의 동작이 변경되었다. Concurrent Rendering이 기본이 되면서, 이전에는 즉시 fallback을 보여주던 것이 이제는 짧은 지연 후에 보여주는 방식으로 바뀌었다. 이는 네트워크가 빠른 경우 불필요한 로딩 UI 깜빡임을 방지하기 위함이다.
해결
Transition API를 활용해 명시적으로 로딩 상태를 관리하도록 수정했다:
import { useState, useTransition, Suspense, lazy } from 'react';
const Dashboard = lazy(() => import('./Dashboard'));
function App() {
const [isPending, startTransition] = useTransition();
const [show, setShow] = useState(false);
const handleClick = () => {
startTransition(() => {
setShow(true);
});
};
return (
<>
{isPending && <Spinner />}
<button onClick={handleClick}>대시보드 열기</button>
{show && (
<Suspense fallback={<Spinner />}>
<Dashboard />
</Suspense>
)}
</>
);
}
라우팅의 경우 React Router v6와 함께 사용하면서 최상위에 Suspense를 배치하고, 각 페이지 전환 시 isPending 상태로 전역 로딩 바를 표시하는 방식으로 통일했다.
정리
React 18의 Concurrent Features는 UX 개선에 초점을 맞췄지만, 기존 코드의 동작 방식이 미묘하게 달라질 수 있다. 특히 Suspense 관련 코드는 업그레이드 후 실제 네트워크 환경에서 테스트가 필요하다.