[성능개선] 성능 향상을 위한 코드 분할하기(React.lazy, Suspense)

서준·2024년 3월 1일
0
post-thumbnail

코드 스필리팅 전

React + TypeScript 방식으로 개발한 프로젝트의 성능개선요소를 고려하던 중 React는 CSR(Client Side Rendering) 방식을 채택하고 있으며 초기 로딩 속도가 느리다는 단점을 개선해보기로 했습니다.

CSR(Client Side Rendering)에 대해 궁금하다면 해당 포스팅을 확인해주세요.

Lighthouse 도구를 통해 검사한 결과 js bundle 사이즈의 개선 가능성을 확인했고 js bundle 사이즈를 줄이고 초기 로딩속도 지연이라는 문제를 해결하기위해 코드분할 방식을 찾게 되었습니다.

코드분할(Code Splitting) 이란?

코드분할은 애플리케이션의 코드를 여러 번에 나누어 로드하는 것을 의미합니다. 이는 초기 로딩 시간을 단축하고 사용자가 페이지에 더 빠르게 접근할 수 있도록 도와주며 React에서는 react.lazySuspense를 사용하여 코드분할을 쉽게 구현할 수 있습니다.

react.lazy란?

React에서 컴포넌트 파일을 코드 최상단으로 불러와 정의하고 동적으로 불러오면 에러가 발생합니다. 하지만 react.lazy 함수를 사용하면 동적으로 컴포넌트를 로드할 수 있습니다.

import React from 'react';
import MyComponent from './MyComponent'; // 일반적인 import
import React, { lazy, Suspense } from 'react';
const MyComponent = lazy(() => import('./MyComponent')); //lazy 함수를 사용한 import

동적으로 로드한 컴포넌트들은 손쉽게 코드분할이 가능하며, 이렇게 로드한 컴포넌트는 Suspense 컴포넌트로 감싸서 로딩 중일 때 보여줄 UI를 지정할 수 있습니다.

import React, { lazy, Suspense } from 'react';

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

function App() {
  return (
    <div>
      <Suspense fallback={<div>로딩중입니다...</div>}> // 로딩 중 보여줄 UI 
        <MyComponent />
      </Suspense>
    </div>
  );
}

React Router와 함께 사용

위 프로젝트 규모가 소규모 프로젝트임을 감안해 웹 페이지를 불러오고 진입하는 단계인 App.js에서 이 두 기능을 적용시켜 사용하였습니다.

import { createBrowserRouter, Navigate } from 'react-router-dom';
import React, { lazy, Suspense } from 'react';
import Loader from './components/Loader';
import NotFound from './pages/NotFound';
import Layout from './Layout';
const Browse = lazy(() => import('./pages/Browse'));
const MyList = lazy(() => import('./pages/MyList'));
const Search = lazy(() => import('./pages/Search'));

const router = createBrowserRouter([
  {
    element: (
      <Suspense fallback={<Loader />}>
        <Layout />
      </Suspense>
    ),
    children: [
      {
        path: '/',
        element: <Navigate to='browse/movie' />,
      },
      {
        path: 'browse/:section',
        element: (
          <Suspense fallback={<Loader />}>
            <Browse />
          </Suspense>
        ),
      },
      {
        path: 'search/:section',
        element: (
          <Suspense fallback={<Loader />}>
            <Search />
          </Suspense>
        ),
      },
      {
        path: 'mylist',
        element: (
          <Suspense fallback={<Loader />}>
            <MyList />
          </Suspense>
        ),
        children: [
          {
            path: ':section',
            element: (
              <Suspense fallback={<Loader />}>
                <MyList />
              </Suspense>
            ),
          },
        ],
      },
      {
        path: '*',
        element: (
          <Suspense fallback={<Loader />}>
            <NotFound />
          </Suspense>
        ),
      },
    ],
  },
]);

export default router;

React Router를 React.lazy와 Suspense와 함께 사용하여 사용자가 Posting 페이지에 접근하면 해당 컴포넌트가 비동기적으로 로드되게 하였고, 사용자가 PostDetail 페이지나 EditPost 페이지에 접근할 때도 마찬가지로 컴포넌트가 필요한 시점에 비동기적으로 로드됩니다.

코드 스플리팅 적용 전

코드 스플리팅 적용 후

이로 인해 위와 같이 초기 페이지 로딩 속도를 2.83초에서 2.23초로(0.6초) 약 21.22% 감소하였으며,
전송 데이터량 또한 211B/6.7MB 에서 221B/105KB으로 줄였으며, 96.72%의 데이터를 감소하였습니다.

코드 분할은 초기 렌더링 시간이 줄어드는 분명한 장점이 있으나 페이지를 이동하는 과정마다 로딩 화면이 보이기 때문에 서비스의 규모와 특성에 맞게 적용 여부를 결정해야 합니다.

References: https://wikidocs.net/197644

profile
하나씩 쌓아가는 재미

0개의 댓글