끄적끄적 코딩
Published 2023. 7. 3. 00:26
[React] 코드 스플리팅 React

리액트로 프로젝트를 생성하고 배포했을 시 웹팩이라는 도구가 별도의 설정없이 모든 자바스크립트 코드와 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 라이브러리 사용을 권장합니다.

검색 태그