리액트 프로잭트에 별도로 설정하지 않으면 코드가 모두 한 파일에 저장되어 버린다. 그렇게 되면 지금 당장 필요하지 않은 컴포넌트 정보도 모두 불러오면서 파일 크기가 매우 커진다. 그러면 로딩이 오래 걸리기 때문에 사용자 경험이 안 좋아지고 트래픽도 많이 나오게 된다. 따라서 파일을 분리하는 작업이 필요한데 이 작업을 코드 스플리팅이라고 한다.
//notify.js
export default function notify(){
alert('안녕하세요');
}
//App.js
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() 함수 형태로 메서드 안에서 사용하면, 파일을 따로 분리시켜서 저장한다.
const onClick = () =>{
import('./notify').then(result => result.default());
};
import 함수를 사용하면 Promise를 반환한다. 이 함수를 통해 모듈을 불러올 때 모듈에서 default로 내보낸 것은 result.default를 참조해야 사용할 수 있다.
React.lazy는 컴포넌트를 렌더링하는 시점에서 비동기적으로 로딩할 수 있게 해 주는 유틸 함수이다.
const SplitMe = React.lazy(() => import ('./SplitMe');
Suspense는 리액트 내장 컴포넌트로서 코드 스플리팅된 컴포넌트를 로딩하도록 발동시킬 수 있고, 로딩이 끝나지 않았을 때 보여 줄 UI를 설정할 수 있다.
import React, {Suspense} from 'react';
<Suspense fallback = {<div>loading...</div>}>
<SplitMe/>
</Suspense>
Suspense에서 fallback props를 통해 로딩 중에 보여 줄 JSX를 지정할 수 있다.
const SplitMe = React.lazy(()=>import('./SplitMe');
function 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'));
function 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>
{visible && <SplitMe/>}
</header>
</div>
);
}
export default App;
로딩 중에 다른 UI를 보여 주고 싶다면
const SplitMe = loadable(() => import('./splitMe'),{
fallback: <div>loading...</div>
});
컴포넌트를 미리 불러오는 방법
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 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;