React

[React] React lazy로 웹 성능 최적화 하기 (코드 스플리팅)

감자당근 2024. 2. 12. 00:28

최근에 리액트로 프로젝트를 하면서 한 번에 여러 컴포넌트들을 불러오게 되면서
웹 성능이 떨어지는 일이 있었습니다.

이에 React.lazy를 통한 코드 스플리팅으로 성능을 개선해보고자 했습니다.

| 코드 스플리팅

리액트에서 개발을 하고 배포할 때 빌드를 하게 되는데 이때 보통 단일 Javascript 파일로 번들링 하게 됩니다.

이 방식은 애플리케이션의 크기가 커지면 초기 로딩 시간이 길어지는 문제를 야기할 수 있어서 코드 스플리팅을 통해 전체 번들을 더 작은 크기로 나누고, 이를 비동기적으로 로드할 수 있게 함으로써 로딩 시간을 개선하게 해주는 것을 코드 스플리팅이라 합니다.

| React lazy

리액트의 lazy와 Suspense필요할 때에 컴포넌트를 로드할 수 있도록 하려면
아래와 같이 코드를 작성하면 됩니다.

import { lazy, Suspense } from 'react';

const Component2 = lazy(() => import('./Component2'));

const Component1 = () => {
  return (
    <div>
      <Suspense fallback={<div>로딩</div>}>
        <Component2 />
      </Suspense>
    </div>
  );
}

여기서 Component2는 Component1이 화면에 렌더링 될 때까지 로딩이 시작되지 않습니다. 
이런 식으로 사용자가 실제로 Component2를 볼 필요가 있을 때까지 해당 컴포넌트로의 로드를 미룰 수 있습니다.

 

여기서 Suspense는 리액트가 컴포넌트의 로드를 기다리는 동안 보여줄 대체 UI를 정의할 수 있도록 해줍니다.

| 적용

제가 작업하던 프로젝트에 react router와 함께 적용해 보겠습니다.

main.tsx파일에서 아래와 같이 여러 컴포넌트를 한 번에 불러와 react router를 적용하고 있습니다.

import Cart from "./pages/Cart";
import Main from "./pages/Main";
import Category from "./pages/Category";
...생략

const router = createBrowserRouter([
  {
    path: "/",
    element: <Main />,
  },
  {
    path: "/cart",
    element: <Cart />,
  },
  {
    path: "/category",
    element: <Category />,
  },
  ...생략
]);

ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
    <RouterProvider router={router} />
  </React.StrictMode>
);

이런 식으로 되면 처음에 페이지에 진입 시 모든 페이지에 대한 정보를 불러오면서 초기 로딩을 느리게 만들 수 있습니다.

 

이때 리액트의 lazy를 사용하면 컴포넌트를 지연 로딩해서 필요한 스크립트를 그때그때 불러오도록 할 수 있습니다.

const Cart = lazy(() => import("./pages/Cart"));
const Main = lazy(() => import("./pages/Main"));
const Complete = lazy(() => import("./pages/Complete"));
...생략

const router = createBrowserRouter([
  {
    path: "/",
    element: <Main />,
  },
  {
    path: "/cart",
    element: <Cart />,
  },
  {
    path: "/category",
    element: <Category />,
  },
  ...생략
]);

ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
    <Suspense fallback={<div>로딩</div>}>
      <RouterProvider router={router} />
    </Suspense>
  </React.StrictMode>
);