조각조각 - CRA 라우팅(코드 분할, lazy 로딩, Suspense)

eocode·2023년 3월 22일
0

리액트 조각조각

목록 보기
9/11
post-thumbnail

React.lazy

지금까지 개인 프로젝트를 진행할때마다 아래 코드처럼 단순하게 모든 페이지 컴포넌트를 불러와 라우트를 구현해왔습니다. 이 경우 SPA이기 때문에 사용하지 않는 컴포넌트들도 모두 불러오게 됩니다. 따라서 페이지 컴포넌트가 많이 존재하거나 페이지 컴포넌트의 크기가 큰 경우 초기로딩 시간이 길어진다는 문제점이 발생합니다. 앞으로 큰 프로젝트 진행 시 좀더 효율적인 라우트 구현을 위해 이 문제의 해결법을 알아보도록 하겠습니다.

//Pages
import Start from "./pages/Start";
import Main from "./pages/Main";
import Profile from "./pages/Profile";
import NotFoundPage from "./pages/NotFoundPage";

function App() {
  return (
    <Router>
      <Routes>
        <Route path="/" element={<Start />} />
        <Route path="main" element={<Main />} />
        <Route path="profile" element={<Profile />} />
      </Routes>
    </Router>
  );
}

위 문제는 라우트 구현 코드가 작성된 App 컴포넌트에서 현재 사용되지 않는 페이지 컴포넌트를 포함해 모든 페이지 컴포넌트를 다 불러와서 사용하기 때문에 발생합니다. 이를 해결하기 위한것이 React.lazy입니다. lazy를 사용하면 컴포넌트를 동적으로 import할 수 있습니다. 즉 페이지가 전환되는 시점마다 해당하는 페이지 컴포넌트만 불러와 사용하기 때문에 App 컴포넌트에서 발생하는 초기 로딩속도가 줄어들게 됩니다.

React.lazy를 사용하지 않는 경우 App 컴포넌트에서 모든 페이지 컴포넌트를 불러와 사용하기 때문에 코드가 하나의 통으로 되어있다고 볼 수 있습니다. 반면에 React.lazy를 사용한다면 필요한 페이지 컴포넌트만 불러와 사용하기 때문에 코드를 분할되었다고 볼 수 있습니다.

무조건 React.lazy를 사용하는것이 옳은가?

React.lazy 사용하는 경우

lazy를 사용하면 초기 로딩시 필요한 코드만 불러와 사용할 수 있습니다. 따라서 초기에 로딩시간이 짧습니다. 반면에 다른 페이지로 전환할때마다 필요한 페이지 컴포넌트를 불러오기 때문에 추가적인 로딩시간을 필요로 합니다.

React.lazy 사용하지 않는 경우

React.lazy 사용하지 않는 경우 초기 로딩시 모든 페이지 컴포넌트 코드를 불러옵니다. 때문에 초기 로딩시 React.lazy를 사용할때보다 많은 로딩 시간을 필요로 합니다. 반면에 초기에 모든 페이지 컴포넌트를 로드했기 때문에 페이지 전환할때마다 페이지 컴포넌트를 로드할 필요없어 추가적인 로딩 시간이 필요하지 않습니다.

정리하자면 React.lazy를 사용할지 말지는 초기 로딩시간을 줄이는 것이 중요한지 초기 로딩시간이 조금 늘어나더라도 페이지 전환 시 로딩 시간이 발생하지 않는 것이 중요한 지에 따라서 고민해보고 선택해야합니다.

사용법

// lazy 사용 X
import Start from "./pages/Start";
import Main from "./pages/Main";
import Profile from "./pages/Profile";

// lazy 사용 O
const Start = lazy(() => import("./pages/Start"));
const Main = lazy(() => import("./pages/Main"));
const Profile = lazy(() => import("./pages/Profile"));

Suspense

lazy를 통한 코드분할을 한 경우 동적으로 컴포넌트를 import 하게되며 컴포넌트가 사용될 때 코드를 불러오게 됩니다. 따라서 lazy로 import한 컴포넌트가 사용될 때 코드를 불러오는데 시간을 필요로 하고 로딩시간을 필요로 하게 됩니다.

로딩중일때 빈공간만을 나타냈다가 로딩이 끝났을때 컴포넌트가 나타나는 것보단 로딩중임을 나타내는 요소를 띄어주는것이 보다 긍정적인 사용자 경험을 일으킵니다. 이를 위해 사용하는 것이 Suspense입니다.

Suspense를 사용하면 렌더링이 준비되지 않은 컴포넌트를 인지하고 로딩화면을 보여줄 수 있습니다.

import React from "react";
import { lazy, Suspense } from "react";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";

//Pages
// import Start from "./pages/Start";
// import Main from "./pages/Main";
// import Profile from "./pages/Profile";

const Start = lazy(() => import("./pages/Start"));
const Main = lazy(() => import("./pages/Main"));
const Profile = lazy(() => import("./pages/Profile"));

function App() {
  return (
    <Router>
      <Suspense fallback={<div>loading...</div>}>
        <Routes>
          <Route path="/" element={<Start />} />
          <Route path="main" element={<Main />} />
          <Route path="profile" element={<Profile />} />
        </Routes>
      </Suspense>
    </Router>
  );
}

export default App;

라우팅 상황이 아닌 lazy와 Suspense

lazy와 Suspense 꼭 라우팅에서만 사용되지 않습니다. 동적으로 특정 컴포넌트를 import하고 싶을때와 동적으로 import한 컴포넌트의 렌더링이 준비되지 않은경우 로딩을 나타내고 싶을때 사용합니다. 따라서 아래와 같이 사용이 가능합니다.

const 지연로딩컴포넌트1 = lazy(() => import("./component/지연로딩컴포넌트1"));
const 지연로딩컴포넌트2 = lazy(() => import("./component/지연로딩컴포넌트2"));
const 지연로딩컴포넌트3 = lazy(() => import("./component/지연로딩컴포넌트3"));

function 특정컴포넌트() {
  return (
    <div>
      <Suspense fallback={<div>loading...</div>}>
      	<지연로딩컴포넌트1 />
      </Suspense>
      <Suspense fallback={<div>loading...</div>}>
      	<지연로딩컴포넌트2 />
      </Suspense>
      <Suspense fallback={<div>loading...</div>}>
      	<지연로딩컴포넌트3 />
      </Suspense>
    </div>
  );
}

멀티 요소 Suspense

위 코드의 경우 지연로딩컴포넌트1, 지연로딩컴포넌트2, 지연로딩컴포넌트3을 각각 Suspence가 감싸서 각각의 컴포넌트의 렌더링 가능 유무를 판단해 로딩임을 나타냅니다. 이 경우 로딩시간에 따라 각각 렌더링 되므로 한번에 세 요소가 렌더링 되지 않습니다.

만약 세 요소가 따로 따로 화면에 렌더링 되지 않고 한번에 렌더링 되기를 원한다면 아래의 코드로 가능합니다. 이 경우 지연로딩컴포넌트1, 지연로딩컴포넌트2, 지연로딩컴포넌트3이 모두 로딩되고 렌더링 가능한 상태일때까지 로딩임을 나타냅니다.

const 지연로딩컴포넌트1 = lazy(() => import("./component/지연로딩컴포넌트1"));
const 지연로딩컴포넌트2 = lazy(() => import("./component/지연로딩컴포넌트2"));
const 지연로딩컴포넌트3 = lazy(() => import("./component/지연로딩컴포넌트3"));

function 특정컴포넌트() {
  return (
    <div>
      <Suspense fallback={<div>loading...</div>}>
      	<지연로딩컴포넌트1 />
        <지연로딩컴포넌트2 />
        <지연로딩컴포넌트3 />
      </Suspense>
    </div>
  );
}

참고자료

profile
프론트엔드 개발자

0개의 댓글