리액트로 프로젝트를 생성하고 배포했을 시 웹팩이라는 도구가 별도의 설정없이 모든 자바스크립트 코드와 CSS 파일을 하나의 파일(main)로 합칩니다.
이 말은 여러 컴포넌트 중 하나의 컴포넌트만 보여진다고 해도 다른 컴포넌트도 자연스래 저장이 된다는 뜻입니다. 이는 파일의 크기를 키우고 로딩이 오래걸려 사용자 경험을 안좋게 할 뿐만 아니라 트래픽도 증가시킬 것 입니다. 이를 해결해 줄 수 있는 방법이 바로 코드 비동기 로딩입니다.
자바스크립트 함수 비동기 로딩
일반 자바스크립트 함수를 스플리팅해 보겠습니다.
notify.js
export default function notify() {
alert('안녕하세요!');
}
src/App.js
//...
function App() {
const onClick = () => {
import('./notify').then(result.default());
};
return (
<div>
<p onClick={onClick}>Hello React!</p>
</div>
)
}
//...
이렇게 import를 함수 형태로 메서드 안에서 사용하면 파일을 따로 분리시켜서 저장합니다. 그리고 실제 함수가 필요한 지점에 파일을 불러와서 사용할 수 있습니다.
import를 함수로 사용하면 Promise를 반환합니다. 이렇게 import를 함수로 사용하는 문법은 비록 아직 표준 자바스크립트가 아니지만 현재 웹팩에서 지원하고 있으므로 별도의 설정없이 사용할 수 있습니다.
이 함수를 통해 모듈을 불러올 때 모듈에서 default로 내보낸 것은 result.default를 참조해야 사용할 수 있습니다.
위 코드를 실행하고 브라우저 개발자 도구의 Network 탭을 열어 버튼을 클릭한다면 클릭 시점에 notify.js 파일을 불러오는 것을 알 수 있습니다.
React.lazy와 Suspense를 통한 컴포넌트 코드 스플리팅
리액트 16.6 버전부터 도입된 유틸 함수인 React.lazy와 컴포넌트인 Suspense를 사용해보겠습니다.
React.lazy와 Suspense 사용하기
다음과 같이 코드를 수정해봅시다.
App.js
import { useState, Suspense } from 'react';
//...
const SplitMe = React.lazy(() => import('./SplitMe'));
function App() {
const [visible, setVisible] = useState(false);
const onClick = () = {
setVisible(true);
}
return (
<div>
<p onClick={onClick}>Hello React!</p>
<Suspense fallback={<div>loading...</div>}>
{visible && <SplitMe />}
</Suspense>
</div>
)
}
//...
위와 같이 해준다면 onClick 클릭 시 로딩 화면 후 불러와진 컴포넌트가 출력될 것 입니다.
개발자 도구 Network 탭에서 Online을 클릭하여 네트워크 속도를 느리게 설정하여 확인해보세요.
Loadable Components를 통한 코드 스플리팅
Loadable Components는 코드 스플리팅을 편하게 하도록 도와주는 서브파티 라이브러리 입니다. 이 라이브러리의 이점은 SSR을 지원한다는 것입니다.
먼저 다음의 명령어로 설치해주세요.
$ yarn add @loadable/component
사용법은 React.lazy와 비슷하나 Suspense를 사용할 필요는 없습니다.
App.js
import loadable from '@loadable/component';
//...
const SplitMe = loadable(() => import('./SplitMe'));
function App() {
const [visible, setVisible] = useState(false);
const onClick = () = {
setVisible(true);
}
return (
<div>
<p onClick={onClick}>Hello React!</p>
{visible && <SplitMe />}
</div>
)
}
//...
로딩 중 다른 UI, 즉 fallback 기능을 사용하고 싶다면 다음과 같이 수정합니다.
App.js
//...
const SplitMe = loadable(() => import('./SplitMe'), {
fallback: <div>loading...</div>
});
//...
만약 특정 트리거를 통해 보이지 않는 컴포넌트를 미리 불러오고 싶다면? 다음과 같이 수정해보세요.
App.js
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>
<p onClick={onClick} onMouseOver={onMouseOver}>
Hello React!
</p>
{visible && <SplitMe />}
</div>
)
}
//...
위처럼 코드를 수정한다면 버튼에 마우스를 올리기만 해도 로딩이 시작되고, 클릭시 렌더링되어 사용자에게 더 좋은 경험을 제공할 수 있습니다.
이밖에도 Loadable Components의 더 다양한 기능을 사용하고 싶다면 다음의 링크를 참고하세요.
정리하자면, 사용자 경험을 위해 코드 스플리팅을 하는것은 좋은 선택이고 그중,
서버 사이드 렌더링 계획이 없다면 React.lazy와 Suspense를, 서버 사이드 렌더링을 할 경우 Loadable Components 라이브러리 사용을 권장합니다.
'React' 카테고리의 다른 글
[React] 서버 사이드 렌더링 (0) | 2023.07.03 |
---|---|
[React] 리덕스를 사용하여 리액트 애플리케이션 상태 관리하기 (0) | 2023.07.01 |
[React] 리덕스 라이브러리 (0) | 2023.07.01 |
[React] Context API (0) | 2023.06.30 |
[React] 리액트 컴포넌트에서 API를 연동 (0) | 2023.06.28 |