리액트 프로젝트를 사용자에게 제공할 때는 빌드 작업을 거쳐서 배포를 함
이러한 빌드 작업은 웹팩 이라는 도구가 담당함
CRA로 프로젝트를 빌드할 경우 최소 두 개 이상의 자바스크립티 파일이 생성됨
이와같이 파일을 분리하는 작업을 코드 스플리팅이라고 함
다만 SplitChunks의 기능을 통한 코드 스플리팅은 단순히 효율적인 캐싱 효과만 보유
당장 사용하지 않는 컴포넌트의 분리를 위해 코드 비동기 로딩이 존재함
본 문서에서는 코드 비동기 로딩 방법으로 3가지를 설명함
자바스크립트에서 다른 파일에 함수를 가져올 때 우리는 import를 사용한다.
이 import 된 파일들은 빌드시에 하나로 합쳐지는데, 자바스크립트에서 이를 분리하고자 한다면 단순히 import를 상단에서 하지 않고 import() 함수 형태로 메서드 안에서 사용하면, 파일을 따로 분리시켜서 저장한다.
// old 버전!
import take from './take'
function app() {
const onclick = () => {
take();
}
}
// new 버전!
function app() {
const onclick = () => {
import('./take').then(result => take().defualt())
}
}
참고로 import를 함수로 사용하면 Promise를 반환한다.
이 방식을 통해 모듈을 불러올 때, 모듈에서 default로 내보낸 것은 result.default를 참조해야 사용 할 수 있다.
코드 스플리팅을 위해 리액트 16.6 버전부터 내장된 기능이다.
이전 버전에서는 import 함수를 통해 불러오고 컴포넌트 자체를 state에 넣는 방식으로 구현을 했었다.
React.lazy는 컴포넌트를 렌더링하는 시점에서 비동기적으로 로딩할 수 있게 해 주는 유틸 함수로 사용방법은 다음과 같다.
const SplitMe = React.lazy(() => import('./SplitMe'));
Suspense는 리액트 내장 컴포넌트로서 코드 스플리팅 된 컴포넌트를 로딩하도록 발동 시킬 수 있고, 로딩이 끝나지 않았을 때 보여 줄 UI를 설정 가능하며 사용방법은 다음과 같다.
import { Suspense } from 'react'
<Suspense fallback={<div>loading...</div>}>
<SplitMe />
</Suspense>
Loadable Components는 서드파티 라이브러리이며 서버 사이드 렌더링을 지원하는 이점이 있다.
또한 렌더링 이전에 필요할 때 스플리팅 된 파일을 미리 불러오는 기능이 존재한다.
다만 본 자료에서는 서버 사이드 렌더링을 제외한 기본적인 사용법만 소개할 예정이다.
라이브러리 설치가 필요하며 명령어는 다음과 같다.
yarn add @loadable/component
사용법은 React.lazy와 비슷하지만 Suspense를 사용할 필요 없다.
import loadable from '@loadable/component';
const SplitMe = loadable(() => import('./SplitMe'));
//본인의 처리하는 코드 등...
<SplitMe />
단순히 선언 부에서 loadable을 사용하고 <SplitMe />
와 같이 원하는 위치에 사용하기만 해도 코드 스플리트가 적용된다.
만약 로딩 중에 다른 UI를 보여주고 싶다면 loadable 사용 부분에 추가 인자를 넘겨주면 된다.
const SplitMe = loadable(() => import('./SplitMe'), {
fallback: <div>loading...</div>
});
컴포넌트를 미리 불러오는 방법은 .preload();
함수를 호출하는 것이다.
다음 예제는 특정 요소에 이벤트를 주어, 마우스를 올리면 로딩을 시작하고, 클릭 시 보여주는 방식이다.
import loadable from '@loadable/component';
const SplitMe = loadable(() => import('./SplitMe'), {
fallback: <div>loading...</div>
});
function app() {
const [visible, setVisible] = useState(false);
const onClick = () {
setVisible(true);
};
const onMouseOver = () {
SplitMe.preload();
};
return (
<div onClick={onClick} onMouseOver={onMouseOver}>
{visible && <SplitMe />}
</div>
)
}
Loadable Components는 미리 불러오는 기능 외에도 타임아웃, 로딩 UI 딜레이, 서버 사이드 렌더링 호환 등 다양한 기능을 제공한다.
다만 React.lazy의 대체제가 아니며 공식 문서에서도 React.lazy를 활용해 스플리팅이 잘 되면 Loadable Components로 바꿀 필요가 없다고 한다.
만약 SSR(서버 사이드 렌더링)이 필요하고, React.lazy에 기능이 제한적이라고 느껴진다면 도입을 고려할만 하다.
링크
[React.lazy VS LoadAble Components 비교 테이블]
라이브러리 | Suspense | SSR | 라이브러리 스플리팅 | import(./${value} ) |
---|---|---|---|---|
React.lazy | ✅ | ❌ | ❌ | ❌ |
@loadable/component | ✅ | ✅ | ✅ | ✅ |
두 방법 다 코드 스플리팅이 주 기능이기 때문에 서버 사이드 렌더링 유무에 따라 선택을 해도 좋다.
내 경우에는 대부분의 프로젝트에서는 추가 라이브러리 대신 React 자체적으로 지원하는 lazy 방식을 택하고, 서버 사이드 렌더링이 필요한 경우에는 Loadable Components를 활용할 예정이다.