파일을 분리하는 작업. 프로젝트에 기본 탑재된 SplitChunks 기능을 이용하면 node_modules에서 불러온 파일,
일정 크기 이상의 파일, 여러 파일 간에 공유된 파일을 자동으로 분리시켜서 캐싱의 효과를 준다.
하지만 리액트 프로젝트에 별도로 설정하지 않으면 컴포넌트에 대한 코드가 모두 한 파일(main)에 저장된다.
만약 애플리케이션의 규모가 커지면 지금 당장 필요하지않은 컴포넌트 정보도 모두 불러오면서 파일 크기가 매우 커진다.
코드 비동기 로딩 방법을 사용하면 자바스크립트 함수, 객체, 혹은 컴포넌트를 처음에는 불러오지 않고 필요한 시점에 불러와서 사용할 수 있다.
export default function notify() {
alert('안녕하세요');
}
import logo from './logo.svg';
import './App.css';
import notify from './notify';
function App() {
const onClick = () => {
notify();
};
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p onClick={onClick}>Hello React!</p>
</header>
</div>
);
}
export default App;
다음과 같이 코드를 작성하고 빌드하면 notify 코드가 main파일 안에 들어가게 된다.
하지만 다음과 같이 import를 상단에서 하지않고 import() 함수 형태로 메서드 안에서 사용하면,
파일을 따로 분리시켜 저장하고 실제 함수가 필요한 지점에 파일을 불러와서 함수를 사용할 수 있다.
import logo from './logo.svg';
import './App.css';
function App() {
const onClick = () => {
import('./notify').then(result => result.default());
};
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p onClick={onClick}>Hello React!</p>
</header>
</div>
);
}
export default App;
import를 함수로 사용하면 Promise를 반환한다.
이 함수를 통해 모듈을 불러올 때 모듈에서 default로 내보낸 것은 result.default를 참조해야 사용할 수 있다.
이 코드를 빌드하면 notify 코드가 main 파일이 아닌 3으로 시작하는 파일 안에 들어간다.
이전 버전에서는 import 함수를 통해 불러온 다음, 컴포넌트 자체를 state에 넣는 방식으로 구현해야했지만,
유틸함수인 React.lazy와 컴포넌트인 Suspense 가 도입된 이후에는 state를 따로 선언하지 않고도 컴포넌트 코드 스플리팅을 할 수 있다.
React.lazy 는 컴포넌트를 렌더링하는 시점에서 비동기적으로 로딩할 수 있게 해주는 유틸함수이다. 사용방법은 다음과 같다.
const SplitMe = React.lazy(() => import('./SplitMe'));
Suspense는 리액트 내장 컴포넌트로서 코드 스플리팅된 컴포넌트를 로딩하도록 발동시킬 수 있고,
fallback props를 통해 로딩이 끝나지 않았을 때 보여줄 UI를 JSX로 지정할 수 있다. 사용방법은 다음과 같다.
import React, { Suspense } from 'react';
(...)
<Suspense fallback={<div>loading...</div>}>
<SplitMe />
</Suspense>
React.lazy와 Suspense를 사용한 예시
import React, { useState, Suspense } from 'react';
import logo from './logo.svg';
import './App.css'
const SplitMe = React.lazy(() => import('./SplitMe'));
const App = () => {
const [visible, setVisible] = useState(false);
const onClick = () => {
setVisible(true);
};
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p onClick={onClick}>Hello React!</p>
<Suspense fallback={<div>loading...</div>}>
{visible && <SplitMe/>}
</Suspense>
</header>
</div>
);
};
export default App;
Loadable Components는 코드 스플리팅을 편하게 하도록 도와주는 서드파티 라이브러리이다.
이 라이브러리의 이점은 서버 사이드 렌더링(웹 서비스의 초기 로딩 속도 개선, 캐싱 및 검색엔진 최적화를 가능하게 해주는 기술)을 지원하고,
렌더링하기 전에 필요할 때 스플리팅된 파일을 미리 불러올 수 있다는 것이다. 사용 방법은 다음과 같다.
import loadable from '@loadable/component';
(...)
const SplitMe = loadable(() => import('./SplitMe'));
로딩 중에 다른 UI를 보여주고 싶다면 loadable을 사용하는 부분을 다음과 같이 수정한다.
const SplitMe = loadable(() => import('./SplitMe'), {
fallback: <div>loading...<.div>
});
컴포넌트를 미리 불러오기 위해서 다음과 같은 코드를 작성할 수 있다.
import React, { useState } from 'react';
import logo from './logo.svg';
import './App.css'
import loadable from '@loadable/component';
const SplitMe = loadable(() => import('./SplitMe'), {
fallback: <div>loading...</div>
});
const App = () => {
const [visible, setVisible] = useState(false);
const onClick = () => {
setVisible(true);
};
const onMouseOver = () => {
SplitMe.preload();
}
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p onClick={onClick} onMouseOver={onMouseOver}>Hello React!</p>
{visible && <SplitMe/>}
</header>
</div>
);
};
export default App;
위 코드는 마우스 커서를 Hello React! 위에 올리기만 해도 로딩이 시작되고 클릭했을 때 렌더링되게 한다.