[React] 코드 분할, lazy, Suspense
코드 분할(Code Spliting)
모던 웹으로 발전하면서 JavaScript 코드가 방대해지고 무거워짐을 개선하기 위해
런타임 시 여러 번들을 동적으로 만들고 불러오는 것
당장 필요한 코드가 아니면 따로 분리시키고, 필요할 때 불러와서 사용
-> 대규모 프로젝트 앱의 경우에도 페이지 로딩 속도를 개선할 수 있음
번들 분할, 줄이는 법
서드 파티 라이브러리(플러그인, 라이브러리, 프레임워크)는 다양한 메서드를 제공하기 때문에 코드 양이 많아
번들링 시 많은 공간을 차지함
-> 라이브러리를 전부 불러와 사용하지 말고, 필요한 것만 불러와 사용하는 것이 성능 개선에 좋음
// 라이브러리 전부 불러오기
import _ from 'lodash';
_.find([]);
// 필요한 메서드만 불러오기
import find from 'lodash/find';
find([]);
React에서의 코드 분할
React는 SPA라서 당장 사용하지 않는 컴포넌트까지 모두 불러오기 때문에
첫화면 렌더링에 시간이 오래 걸림
-> 사용하지 않는 컴포넌트는 나중에 불러오기 위해 코드 분할 개념을 도입함
기존: 정적 분할(Static Import)
- 문서의 상위에서 라이브러리와 파일을 import함(코드 구조의 중심을 잡아줌)
- 블록문 안에 위치할 수 없음
-> 번들링 시 코드 구조를 분석해 모듈을 모으고 사용하지 않는 모듈을 제거하기 때문에 코드 구조가 간단하고 고정되어 있어야했음
/* 기존에는 파일의 최상위에서 import를 이용해 라이브러리 및 파일을 불러옴 */
import moduleA from "library";
form.addEventListener("submit", e => {
e.preventDefault();
someFunction();
});
const someFunction = () => {
/* 코드 중간에서 불러온 파일을 사용 */
}
동적 분할(Dynamic Import)
- 코드의 중간에서 모듈을 불러올 수 있음(import, then)
- 가져온 코드의 호출은 해당 함수 내부에 있어야 함
-> 구문 분석 및 컴파일해야하는 스크립트 양을 최소화하기 위해 사용하며 then으로 필요한 코드만 가져옴
번들링 시 분할된 코드(청크)를 지연 로딩시키거나, 요청 시 로딩할 수 있음
form.addEventListener("submit", e => {
e.preventDefault();
/* 코드의 중간에서 모듈을 불러옴 */
import('library.moduleA')
.then(module => module.default)
.then(someFunction())
.catch(handleError());
});
const someFunction = () => {
/* moduleA 사용 */
}
import(module)
모듈을 읽어 모듈의 내용을 모두 포함한 객체를 담은 프로미스 반환
import는 함수가 아니기 때문에 변수에 import를 복사하거나 call/apply 사용 불가
React.lazy()
dynamic import로 컴포넌트를 렌더링할 수 있게 해줌
-> 컴포넌트를 분리하여 초기 렌더링 시간을 줄여줌
React.Suspense 하위에서 렌더링해야 함
React.Suspense
Router로 분기가 나누어진 컴포넌트들을 lazy를 통해 import하면,
해당 path로 이동할 때 컴포넌트를 불러오는데 이 때 로딩 시간이 생기게 됨
아직 렌더링이 준비되지 않은 컴포넌트가 있으면 fallback 속성으로 설정한 로딩화면을 보여줌
lazy, Suspense 적용 시 웹 페이지를 불러오고 진입하는 Route에 적용시키는 것이 좋음
(코드 분할을 도입할 곳을 결정하는 것이 까다롭기 때문에)
import { Suspense, lazy } from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
const Home = lazy(() => import('./routes/Home'));
const About = lazy(() => import('./routes/About'));
const App = () => (
<Router>
<Suspense fallback={<div>Loading...</div>}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</Suspense>
</Router>
);
동적으로 컴포넌트를 불러오는 것에 장단점이 있기 때문에 서비스에 따라 적용 여부를 결정해야 함
장점: 초기 렌더링 시간이 줄어듦
단점: 페이지 이동 시마다 로딩 화면이 보여짐
2023.01.25
코스 S4U4 코드 분할, React.lazy, React.Suspense