3. React.lazy와 Suspense를 통한 컴포넌트 코드 스플리팅
코드 스플리팅(분할) 작업을 위해 리엑트에 내장된 기능으로 유틸함수인 React.lazy와 컴포넌트인 Suspense가 있습니다. 먼저 두개의 내장 기능에 대해서 알아 보겠습니다.
주의사항!!
react v16.6 버전 이후부터 React.lazy와 Suspense 컴포넌트 사용이 가능합니다.
그 전 버전에서는 import 함수를 통해서 불러온다음, 컴포넌트 자체를 state에 넣는 방식으로 구현해야 합니다.
(이전 글참고)
3.1 React.lazy와 Suspense
React.lazy란?
컴포넌트를 렌더링하는 시점에서 비동기적으로 로딩할 수 있게 해 주는 유틸 함수입니다.
Suspense란?
리액트 내장 컴포넌트. 코드 분할된 컴포넌트를 로딩하도록 할 수 있고, 로딩이 끝나지 않았을 때 보여줄 UI를 설정할 수 있습니다.
두가지 내장기능의 차이점
가장 큰 차이점은 React.lazy는 함수이고, Suspense는 컴포넌트라는 점입니다.
3.2 state를 사용한 코드 스플리팅
React.lazy를 사용하기 전에, 해당 유틸함수 없이 컴포너트 코드를 스플리팅한다면 어떻게 해야하는지 먼저 알아 보겠습니다.
먼저 코드 스플리팅을 할 컴포넌트를 간단하게 만들겠습니다.
- SplitMe.js
const SplitMe = () => {
return <div>SplitMe</div>;
};
export default SplitMe;
App 컴포넌트를 클래스형 컴포넌트로 전환 하겠습니다.
그리고 handleClick 메서드를 생성하고, 그 내부에서 SplitMe 컴포넌트를 불러와서 state에 넣겠습니다.
또한 render 함수에서는 SplitMe가 유효하다면 SplitMe 컴포넌트를 렌더링되도록 해주어야 합니다.
- App.js
import logo from "./logo.svg";
import "./App.css";
import { Component } from "react";
class App extends Component {
state = {
SplitMe: null,
};
handleClick = async () => {
const loadedModule = await import("./SplitMe");
this.setState({
SplitMe: loadedModule.default,
});
};
render() {
const { SplitMe } = this.state;
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p onClick={this.handleClick}>Hello React!</p>
{SplitMe && <SplitMe />}
</header>
</div>
);
}
}
export default App;
이제 브라우저 개발자 도구에서 Network 탭을 열고 Hello React!를 눌러 보세요.
그리고 SplitMe 컴포넌트의 코드가 스플리팅 되었는지 확인해보세요.
state를 사용하여 컴포넌트 코드 스플리팅을 하는 것이 어렵지는 않지만, 매번 state를 선언해 주어야 한다는 단점이 있습니다.
3.2 React.lazy와 Suspense 사용하기
React.lazy와 Suspense를 사용하면 코드 스플리팅을 하기 위해 state를 따로 선언하지 않고 간단하게 컴포넌트 코드 스플리팅을 할 수 있습니다. 먼저 방금 만든 컴포넌트에 적용해보겠습니다.
React.lazy 사용법은 아래와 같습니다.
const SplitMe = React.lazy(() => import('./SplitMe'));
Suspense 사용법은 아래와 같습니다.
import { Suspense } from 'react';
(...)
<Suspense fallback={<div>loading...</div>}>
<Splitme />
</Suspense>
Suspense에서는 fallback props 설정을 통해서 로딩중에 보여줄 jsx도 지정할 수 있습니다.
이제 해당 기능을 프로젝트에 적용해보겠습니다.
사용할 필요가 없는 class형을 다시 함수형으로 전환하겠습니다.
- App.js
import logo from "./logo.svg";
import "./App.css";
import React, { Suspense, useState } from "react";
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;
단순히 SplitMe 컴포넌트를 구분하는 visiable라는 상태만 업데이트하여 코드스플리팅된 컴포넌트를 보여주도록 하였습니다.
아래와 같이 개발자도구를 설정하여 네트워크 속도를 느리게 설정해주세요.
- F12
- Network
- Online
- Slow 3G 클릭
느린 네트워크를 시뮬레이트하여 로딤문구가 잘 나타나는지를 확인해 보세요.
확인 후에는 인터넷속도를 다시 원래대로 변경 해주세요.
3.3 Loadable Components를 통한 코드 스플리팅
LoadedAble Components란?
LoadedAble Components는 코드 스플리팅을 편하게 할 수 있도록 도와주는 서드파티의 라이브러리입니다.
이 라이브러리의 장점은 SSR(서버 사이드 랜더링)을 지원한다는 장점이 있습니다.
위의 2가지 기능은 CSR(클라이언트 사이드 랜더링)만 지원하고 아직까지 서버사이드 랜더링을 지원하지 않습니다.
또한 React 공식문서에서도 현재는 SSR사용을 위해서는 이 서드파티 라이브러리 사용을 권장하고 있습니다.
먼저 아래의 라이브러리를 설치해 주세요.
yarn add @loadable/component
이제 App.js를 수정 하겠습니다
- App.js
import logo from "./logo.svg";
import "./App.css";
import loadable from "@loadable/component";
import { Suspense, useState } from "react";
const SplitMe = loadable(() => import("./SplitMe"), {
fallback: <div>...로딩중</div>,
});
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;
.
동일하게 로딩되는지 확인해 보세요.
이번에는 컴포넌트를 미리 불러오는 방벙블 알아 보겠습니다.
아래와 같이 코드를 수정해주세요.
- App.js
import logo from "./logo.svg";
import "./App.css";
import loadable from "@loadable/component";
import { useState } from "react";
const SplitMe = loadable(() => import("./SplitMe"), {
fallback: <div>...로딩중</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;
이렇게 하시면 마우스 커서를 Hello React 위에 올리기만 해도 로딩을 보여줄 수 있습니다.
그리고 클릭하면 렌더링이 되겠죠.
마우스를 올렸을 떄 js 파일이 로드되는지를 확인해보세요.
위와 같은 라이브러리를 사용하면 사전에 필요한 정보를 미리 보여줌으로써 사용자 경험을 향상시킬때 도움을 줄 수 있습니다.
이외에도 Loadable Components가 제공하는 다양한 기능은 아래 공식문서에서 확인 하실 수 있습니다.
Loadable Components
The recommended Code Splitting library for React.
loadable-components.com
3.4 gitHub 주소
GitHub - S-YC/code-splitting: 코드 스플리팅 학습하기
코드 스플리팅 학습하기. Contribute to S-YC/code-splitting development by creating an account on GitHub.
github.com
'프론트엔드 > React' 카테고리의 다른 글
[프론트엔드] 서버 사이드 랜더링[2] (0) | 2022.06.09 |
---|---|
[프론트엔드] 서버 사이드 랜더링[1] (0) | 2022.06.08 |
[프론트엔드] 코드 스플리팅 [2] (0) | 2022.06.06 |
[프론트엔드] 코드 스플리팅 [1] (0) | 2022.06.05 |
[프론트엔드] 리덕스 미들웨어를 통한 비동기 작업 관리[10] (0) | 2022.06.03 |