Frontend/ReactJS

컴포넌트 코드 스플리팅

findmypiece 2021. 3. 4. 01:15
728x90

findmypiece.tistory.com/16?category=966881

 

코드 스플리팅(spliting)

리액프 프로젝트를 실제 서버에 배포할 때는 별도의 빌드 작업을 거쳐야 한다. 자바스크립트 파일 안에서 불필요한 주석, 경고메시지, 공백 등을 제거해서 파일의 크기를 최소화하고 jsx문법이

findmypiece.tistory.com

위에서 포스팅 했듯이 리액트 빌드시 웹팩에서 기본적인 코드 스플리팅은 해주지만

프로젝트에서 작성하는 코드들도 한 파일로 합쳐지지 않도록 코드 스플리팅이 필요하다.

그 방법으로 컴포넌트 자체를 지연로딩 하는 방법이 있다.

 

이를 통해 초기 렌더링에 필요없는 컴포넌트들은 로딩 하지 않아 로딩시간도 짧아지고

트래픽도 절약할 수 있다.

그리고 이렇게 지연로딩 되는 컴포넌트는 웹팩 빌드시

별도 파일로 합쳐지기 때문에 브라우저 캐시 효율성도 증가한다.

 

이는 기본적으로 ES6에 추가된 dynamic import 문법을 활용하는 것인데

Promise 기반으로 import를 동적으로 수행할 수 있게 해준다.

다만 이것을 활용하려면 컴포넌트 에서 매번 state를 선언해서

지연로딩으로 읽어온 컴포넌트를 넣는 방식으로 구현해야 한다.

조건부 렌더링을 구현하려면 state 와 같은 가변적인 상태가 필요하기 때문.

 

그런데 리액트 16.6 버전부터 도입된 React.lazy와 Suspense를 활용하면

state를 선언하지 않고도 간편하게 동적 컴포넌트 지연로딩을 구현할 수 있다.

 

React.lazy 는 유틸 함수이고 Suspense는 리액트 내장 컴포넌트인데

React.lazy는 컴포넌트를 렌더링 하는 시점에 비동기적으로 로딩할 수 있게 해주고

Suspense는 이렇게 비동기적으로 로딩되는 동안 보여줄 UI를 설정할 수 있게 해준다.

 

구현은 대략 아래와 같이 하면 되고

CounterContainer 컴포넌트가 실제 렌더링 될때 import 가 수행되게 된다.

import React, {useState, Suspense} from 'react';
import TodosContainer from "./containers/TodosContainer";

const CounterContainer = React.lazy(() => import('./containers/CounterContainer'));

const App = () => {
  const [viewCounter, setViewCounter] = useState(false);
  const onClick = () => {
    setViewCounter(true);
  }

  return (
      <div>
        <button type="button" onClick={onClick}>카운터세기</button>
        <Suspense fallback={<div>loading...</div>}>
          {viewCounter && <CounterContainer />}
          {viewCounter && <hr />}
        </Suspense>
        <TodosContainer />
      </div>
  );
};

export default App;

 

그런데 리액트 버전 문제인지 내가 설치한 리액트 버전(17.0.1)에서는 제대로 동작하지 않았다.

 

그래서 나는 Loadable Components를 사용해서 컴포넌트 지연로딩을 구현했다.

이는 컴포넌트 지연로딩을 도와주는 서드파티 라이브러리로 React.lazy/Suspense 와 다르게

서버 사이드 렌더링을 지원한다. 리액트 공식문서에서도 서버 사이드 렌더링을 할 경우

Loadable Components 를 사용하도록 권장한다고 한다.

또한 서드파티 라이브러리답게 컴포넌트가 렌더링 되지 않더라도

파일을 미리 로딩할 수 있는 추가 기능도 제공한다.

그냥 처음부터 이걸 쓸 걸 그랬다..

 

우선 Loadable Components 라이브러리를 설치해야 한다.

yarn add @loadable/component

 

사용법은 대략 아래와 같다.

import React, {useState} from 'react';
import loadable from '@loadable/component';
import TodosContainer from "./containers/TodosContainer";

const CounterContainer = loadable(
    () => import('./containers/CounterContainer'),
    {fallback: <div>loading</div>});

const App = () => {
  const [viewCounter, setViewCounter] = useState(false);
  
  const onClick = () => {
    setViewCounter(true);
  }

  const onMouseOver = () => {
    CounterContainer.preload();
  }

  return (
      <div>
        <button type="button" onClick={onClick} onMouseOver={onMouseOver}>카운터세기</button>
        {viewCounter && <CounterContainer />}
        {viewCounter && <hr />}
        <TodosContainer />
      </div>
  );
}

export default App;

React.lazy 와 비슷한데 Suspense 컴포넌트를 별도 정의할 필요없이 함수 사용시 옵션으로 설정할 수 있다.

옵션인만큼 fallback 설정은 필요없다면 정의하지 않으면 된다.

React.lazy/Suspense 때와는 다르게 버튼에 onMouseOver 이벤트가 추가되었는데

preload() 를 통해 렌더링 전에 파일을 미리 로딩할 수 있다.

728x90

'Frontend > ReactJS' 카테고리의 다른 글

외부 js, css 파일 사용하기  (0) 2021.03.04
useEffect  (0) 2021.03.04
코드 스플리팅(spliting)  (0) 2021.03.03
json-server 를 이용한 테스트용 api 서버 구성  (0) 2021.03.03
리액트 프로젝트 디렉토리 구조  (0) 2021.03.03