컴포넌트 비동기 렌더링의 기본
리액트 컴포넌트를 스플리팅 하는것도 이전에 notify 함수를 스플리팅 했던 방식과 똑같은 방식으로 할 수 있습니다.
한번 SplitMe 라는 컴포넌트를 만들어보세요:
src/SplitMe.js
import React from 'react';
const SplitMe = () => {
return <div>리액트 컴포넌트를 코드스플리팅 하자.</div>;
};
export default SplitMe;
스플리팅 하고싶은 컴포넌트 내부에서는 딱히 특별한 작업을 하실 필요 없습니다. 그 대신에, 이 컴포넌트를 불러와서 사용하는 곳에서 import 를 통하여 비동기적으로 불러오면 됩니다.
이제, App 컴포넌트에서 리액트 로고를 누르게 됐을 때 SplitMe 컴포넌트를 불러와서 state 안에 넣어보겠습니다. 그리고 render 함수 내부에서는 SplitMe 컴포넌트가 성공적으로 불러와지고 난 다음에 컴포넌트에서 렌더링하도록 코드를 작성해보겠습니다.
src/App.js
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
class App extends Component {
state = {
SplitMe: null
};
handleClick = () => {
import('./SplitMe').then(result => {
this.setState({
SplitMe: result.default
});
});
};
render() {
const { SplitMe } = this.state;
return (
<div className="App">
<img
src={logo}
className="App-logo"
alt="logo"
onClick={this.handleClick}
/>
<p>Hello React!</p>
{SplitMe && <SplitMe />}
</div>
);
}
}
export default App;
위 코드는 async/await 를 사용하면 다음과 같이 작성 될 수 있습니다.
handleClick = async () => {
const result = await import('./SplitMe');
this.setState({
SplitMe: result.default
});
};
그런데, 모든 컴포넌트마다 state 를 만들어서 관리하기는 참 번거로울 것입니다. 때문에, 이를 함수화하여 더욱 쉽게 코드 스플리팅을 할 수 있도록 해주는 유틸 함수를 만들어서 코드 스플리팅을 해보겠습니다.
src 디렉토리에 withSplitting.js 이라는 파일을 만들어서 다음 함수를 작성해주세요:
src/withSplitting.js
import React, { Component } from 'react';
const withSplitting = getComponent => {
// 여기서 getComponent 는 () => import('./SplitMe') 의 형태로 함수가 전달되야합니다.
class WithSplitting extends Component {
state = {
Splitted: null
};
constructor(props) {
super(props);
getComponent().then(({ default: Splitted }) => {
this.setState({
Splitted
});
});
}
render() {
const { Splitted } = this.state;
if (!Splitted) {
return null;
}
return <Splitted {...this.props} />;
}
}
return WithSplitting;
};
export default withSplitting;
이 함수가 있다면, 더 이상 App.js 내부에서 상태안에 컴포넌트를 넣을 필요 없습니다. 그 대신에 불러오는 과정에서 이 함수를 통해 불러오시면 됩니다.
App 컴포넌트를 다음과 같이 수정해보세요:
src/App.js
import React, { Component } from 'react';
import withSplitting from './withSplitting';
import logo from './logo.svg';
import './App.css';
// 불러올 때 이렇게 withSplitting 으로 감싸서 불러옵니다.
const SplitMe = withSplitting(() => import('./SplitMe'));
class App extends Component {
state = {
visible: false
};
handleClick = () => {
this.setState({
visible: true
});
};
render() {
const { visible } = this.state;
return (
<div className="App">
<img
src={logo}
className="App-logo"
alt="logo"
onClick={this.handleClick}
/>
<p>Hello React!</p>
{visible && <SplitMe />}
</div>
);
}
}
export default App;
이전에는 우리가 state 안에 컴포넌트 자체를 담아줬엇지만, 이제는 visible 값에 따라 컴포넌트가 렌더링 될지말지 정하고있습니다.
이제는 우리가 단순히 렌더링만 해주면, 렌더링 되는 시점에서 자동으로 스플리팅된 파일의 로딩이 시작되고, 파일을 다 불러오고나서 컴포넌트가 렌더링이 됩니다.