번들러로 전체 의존성을 관리하여 하나의 app.js 파일로 실행파일을 만드는 건 편리하지만, 프로젝트 규모가 커지면 파일 하나의 용량이 커지게 되고, 의존성을 전부 한번에 로딩하게 되면 로딩시간이 길어지게 되는 단점.
필요한 컴포넌트만 로딩하는 방법을 코드 스플리팅이라고 함. 필요한 컴포넌트만 비동기적으로 로딩하게 되면 로딩도 빠르게 이루어지고 트래픽도 줄어 사용자 경험이 좋아질 수가 있다.
웹팩에서 지원하는 dynamic import는 import를 함수처럼 사용하여 Promise로 반환하는 비동기 방식이다. 원하는 함수 형태로 써서 필요할 때만 import를 한 뒤, 돌아오는 promise에서 모듈을 실행할 수 있도록 만드는 것이라고 생각하면 된다.
예시
export default function notify() {
console.log('notify');
}
// src/App.js
import React from 'react';
function App() {
const onClick = () => {
import('./notify').then(res => res.default());
};
return (
<div>
<p onClick={onClick}>Hello World</p>
</div>
);
}
export default App;
React 라이브러리에 내장된 React.lazy로도 dyanamic import를 할 수 있다.
이 때, React.lazy로 동적 import를 하는 컴포넌트의 fallback 설정을 위해선 컴포넌트를 Suspense 컴포넌트 안에 감싸줘야 한다. 즉 dynamic import는 lazy, lazy를 로딩하는 동안의 fallback 설정은 suspense로 나뉘어져 있다. suspense는 lazy 로딩 컴포넌트의 Direct parent일 필요는 없으며, 여러 개의 lazy loading 컴포넌트를 자식 컴포넌트로 가질 수도 있다. 리액트 라이브러리에 내장되어있긴 하지만 아직 정식지원은 하고 있지 않다.
예시
import React, { lazy, Suspense } from 'react';
const NewPopup = lazy(() => import('./views/NewPopup'));
const Loading = () => <p>Loading</p>;
const MainComponent = () => (
<Suspense fallback={<Loading/>}>
<NewPopup />
</Suspense>
)
loadable-component는 자체적으로 fallback 설정 및 dynamic import가 가능하고, 서버사이드 렌더링도 지원한다. 아직은 React.lazy나 suspense보다 더 사용하기 용이하다.
loadable-components 사용예시
const Login = loadable(() => import('@pages/login'));
const SplitMe = loadable(() => import("./SplitMe"), {
fallback: <div>로딩중입니다</div>,
});
공통된 페이지 레이아웃을 활용하는 방법
1. 공통된 레이아웃 컴포넌트에 children props를 준 후 서로 다른 페이지 컴포넌트를 레이아웃 컴포넌트로 감싼다.
타입스크립트에서 children props가 있는 컴포넌트는 FC이고, children props가 없는 컴포넌트는 VFC이다. props를 제네릭으로 관리하면 편하다.
const Menu: VFC<{name:string, List:string[]}> = ({name, List})=>{
return(
<div>
{name}
<ul>
{List.map(data=> <li>data</li>)}
</ul>
</div>
)
}