지식 정리 📝

React Lazy + Suspense 사용 시 페이지 전환 깜빡임(흰 화면) 문제 해결

엄성준 2026. 3. 23. 20:15
728x90

이전에 WiniLogis 프로젝트의 성능 최적화를 진행하면서 코드 스플리팅을 적용한 경험이 있습니다.

 

기존에는 SPA 특성상 메인 페이지에 접속하면 모든 페이지의 리소스가 하나의 JS 파일로 번들링되어 로드되고 있었습니다.


이로 인해 초기 로딩 시 불필요한 코드까지 함께 로드되는 문제가 있었습니다.

 

이를 개선하기 위해 React의 Lazy와 Suspense를 활용하여 도메인 단위로 파일을 분리하고, 필요한 시점에만 리소스를 불러오도록 구조를 변경했습니다.

 

그 결과 메인 페이지에서 로드되는 코드 양을 281,862줄 → 63,303줄로 줄이며 성능을 개선할 수 있었습니다.

 

또한 이외에도 이미지 리소스 최적화, i18n 기반 다국어 처리 개선 등을 함께 진행하며 전반적인 성능 점수와 접근성 점수도 개선할 수 있었습니다.


문제 상황

Before

코드 스플리팅 적용 이후, 한 가지 문제가 발생했습니다.

 

페이지 이동 시마다 화면이 순간적으로 사라지며 흰 화면이 노출되는 현상이 있었습니다.

 

또한 SPA임에도 불구하고 페이지 전환이 자연스럽지 않고 뚝뚝 끊기는 느낌을 받게 되었습니다.


원인

App 최상단에서 Suspense를 다음과 같이 사용하고 있었습니다.

 

App.tsx

/* Lazy Loading 적용 */
const Main = lazy(() => import('./components/main'));

export default function App() {
  return (
    <Suspense fallback={<></>}>
      <Routes>
        <Route path='/' element={<Main />} />
        ...
      </Routes>
    </Suspense>
  );
}

 

fallback을 비워둔 이유는 다음과 같았습니다.

  • 페이지별 API 로딩은 각 페이지에서 개별적으로 처리
  • 페이지 전환 시 글로벌 로딩 UI는 UX적으로 적절하지 않다고 판단

하지만 이 구조로 인해 lazy 컴포넌트가 로딩되는 순간 Suspense가 fallback을 렌더링하게 되고, 결과적으로 화면이 비워지면서 흰 화면이 노출되는 문제가 발생했습니다.


고민한 점

이 문제를 해결하기 위해 몇 가지 방향을 고민했습니다.

 

하지만 이 방식은 각 컴포넌트마다 Suspense와 fallback 처리를 별도로 해줘야 하고, 그에 따라 관리 포인트가 늘어나면서 코드 복잡도가 증가할 수 있다고 판단했습니다.

 

또한 React의 Suspense 자체를 걷어내고, 코드 스플리팅 없이 일반적인 SPA 구조로 사용하는 방안도 함께 고민했습니다.

 

하지만 현재 프로젝트의 규모가 큰 상황에서 청킹을 제거할 경우 100KB 이상 크기의 번들 파일이 다수 발생하게 되고, 이는 초기 로딩 성능에 부정적인 영향을 다시 줄 수 있다고 판단했습니다.

 

결과적으로 코드 스플리팅 구조는 유지하면서 UX 문제를 해결할 수 있는 방향 을 찾는 것이 필요했습니다.


해결 과정

이후 해결 방법을 찾던 중, react-router-dom v7_startTransition 옵션을 통해 문제를 해결할 수 있었습니다.

 

index.tsx

...

root.render(
  <>
    <BrowserRouter future={{ v7_startTransition: true }}>
      <App />
    </BrowserRouter>
  </>
);

 

해당 옵션을 활성화하면 라우트 전환이 내부적으로 React의 startTransition으로 감싸지게 됩니다.

 

startTransition은 상태 업데이트를 transition으로 처리하여, 작업이 진행되는 동안 기존 UI를 유지할 수 있도록 도와주는 기능입니다.

 

기존에는 페이지 전환 시 lazy 컴포넌트가 로딩되면서 Suspense에 의해 fallback UI가 즉시 렌더링되었고, 이로 인해 흰 화면이 노출되었습니다.


하지만 이 옵션을 적용한 이후에는 페이지가 suspend되더라도 transition 상태로 처리되기 때문에 기존 화면이 유지된 채 로딩이 진행됩니다.

 

그 결과 lazy 컴포넌트 로딩 중에도 fallback(<></>)이 즉시 노출되지 않고 기존 화면이 유지되며, 로딩이 완료된 시점에 자연스럽게 다음 화면으로 전환되어 사용자 입장에서는 끊김 없이 페이지가 전환되는 것처럼 느껴지게 되었고, 페이지 이동 시 발생하던 흰 화면 문제를 해결할 수 있었습니다.

 

After (페이지 전환 과정에서 흰 화면이 발생하는 것처럼 보일 수 있으나, 실제 동작에는 흰 화면이 발생하지 않습니다.), 화면이 번쩍이는건 mov to gif 파일 변환 중 발생한것으로 보입니다.


느낀 점

처음에는 코드 스플리팅 구조나 Suspense 사용 방식의 문제라고 생각해, 청킹 단위를 더 세분화하거나 구조를 변경하는 방향을 고민했습니다.

 

하지만 큰 구조를 변경하지 않고도 옵션 한 줄로 문제를 해결할 수 있었고, 이번 경험을 통해 또 하나를 배울 수 있었습니다.

 

또한 개발이 끝난 이후, react-router-dom을 v7으로 업데이트하면 v7_startTransition 옵션이 기본적으로 적용되어 별도의 설정 없이도 동일한 효과를 얻을 수 있다는 점을 알게 되었습니다. 이에 따라 react-router-dom을 7버전 이상으로 업데이트했습니다.