[React.Lazy][Suspense] React에서 코드 스플리팅하기

GY·2022년 5월 15일
0

리액트

목록 보기
53/54
post-thumbnail

입사 첫 주차가 지나갔다.
앞으로 매주 TWIL과 회고를 진행하려고 하는데,
오늘은 회사의 코드를 파악하면서 익숙하지 않은 새로운 개념들을 하나씩 정리해두려고 한다.
회사에서는 Next.js를 별도로 사용하고 있지는 않고 React 자체에서 코드 스플리팅을 사용하고 있다.
이 부분에 대해 정리해보자.

코드 스플리팅

SPA에서는 모든 코드를 처음 접속했을 때 서버에서 클라이언트로 요청해 받아온다.
즉, 사용자가 접속하지 않은 페이지에 관련된 코드도 함께 전송 받기 때문에, 프로젝트의 규모가 크다면 다운받는 코드의 용량이 커진다는 단점이 있다.
이 때 사용할 수 있는 것이 코드 스플리팅으로,
접속한 페이지에서 당장 필요한 코드만 받고, 나머지는 필요할 때만 요청해서 새로 받아 사용하는 기법을 말한다.

CRA에서 제공하는 Split Chunks로도 코드 스플리팅이 기본적으로 되기는 하나, 이러한 용도로 사용하기는 어렵다.

Split Chunks?

CRA에서는 기본 설정된 웹팩이 Split Chunks 기능을 사용해 빌드 시 라이브러리 관련 코드를 분리한다.
따라서 캐싱 기능의 이점을 더 오래 누릴 수 있다는 장점이 있다.
단 라이브러리 관련 코드를 분리할 뿐 모든 컴포넌트가 한 곳에 저장되므로, 우리가 원하는대로 js 코드를 분리해 원할 때만 사용할 수는 없다.

코드스필리팅을 위해서 이전에는 import함수를 통한 비동기 로딩과 클래스형 컴포넌트를 사용했다.
React v16.6 이후부터는 코드 스플리팅을 위한 내장함수인 React.Lazy, Suspense 컴포넌트가 도입되었다.

React.Lazy

React.Lazy는 코드스플리팅에 사용하는 메서드로, dynamic import로 사용할 컴포넌트를 가져올 수 있다.

Dynamic import

import()
아직 웹표준은 아니지만 stage-3단계에 있다.
이 메서드는 promise를 반환하며, 모듈을 비동기적으로 common JS형태로 불러온다. 따라서 따로 default를 명시해 주어야 한다.

Suspense

import한 컴포넌트는 Suspense의 내부에서 호출해 사용할 수 있다.

Suspense - fallback

Suspense의 fallback 속성은 해당 컴포넌트를 가져오는 데 걸리는 시간 동안 렌더할 일종의 로더를 지정할 수 있다.

import React, { Suspense, useState } from "react";
import "./App.css";

const SplitMe = React.lazy(() => import("./SplitMe"));//1. dynamic import()

function App() {
  const [visible, setvisible] = useState(false);
  return (
    <div>
      <button
        onClick={() => {
          setvisible(true);
        }}
      >
        가져오기
      </button>
      <Suspense fallback={<div>로딩중입니다...</div>}> 
        {visible ? <SplitMe /> : null} 
		// 2. Suspense 내부에서 import한 컴포넌트 호출
		// fallback 속성으로 해당 컴포넌트를 가져오기 전까지 렌더링 할 요소를 지정해주면 로딩화면 구현가능
      </Suspense>
    </div>
  );
}

export default App;

코드스플리팅과 서버사이드 렌더링

React.Lazy와 Suspense는 아직 서버사이드 렌더링이 불가능하다.
그 이전에, 코드 스플리팅을 서버사이드 렌더링과 함께 구현한다면 몇 가지 문제점이 발생할 수 있다.

문제1. 서버에서는 리렌더링이 없다

서버사이드 렌더링에서는 우리가 컴포넌트를 문자열 형식으로 렌더링하는데,
도중에 state가 바뀐다고 해서 문자열이 혼자 바뀌지는 않는다.

NormalModuleReplacementPlugin

그래서 아예 서버에서는 코드스플리팅을 적용하지 않고,프로덕션 브라우저 코드에서만 코드 스플리팅된 모듈을 사용하도록 할 수 있다.

문제2. 페이지 깜박임 현상

코드 스플리팅과 서버사이드 렌더링을 함께 하게 되면 다음과 같은 과정이 진행된다.

  1. 서버에서 HTML을 생성해 클라이언트에게 전달해준다.
  2. 클라이언트는 전달받은 HTML을 페이지에 보여준다.
  3. JS가 실행되고, 스플리팅된 코드가 아직 로딩되지 않아 null이 렌더링되면서 보여주었던 요소가 화면에서 사라진다.
  4. 컴포넌트를 로딩한 다음에는 다시 렌더링을 한다.

이 문제를 방지하기 위해서는 사전에 어떤 경로로 들어왔을 때 어떤 컴포넌트를 불러와야 하는지 따로 정의해두고, 코드 로딩이 끝난 다음에 ReactDOM.render함수를 호출하는 방법이 있따.

React-loadable

위 방법보다 조금 더 쉽게 코드스플리팅과 서버사이드 렌더링을 함께 진행하려면 react-loadable을 사용할 수 있다. 이 부분에 대해서는 다음 포스팅에서 다루어볼 예정이다.

서버에서 렌더링 된 앱에서 코드 분할을 하기 위해서는 어떻게 해야 할까?

Loadable Components


Reference

profile
Why?에서 시작해 How를 찾는 과정을 좋아합니다. 그 고민과 성장의 과정을 꾸준히 기록하고자 합니다.

0개의 댓글