리액트에 대해서는 개인적으로 생활코딩님의 강의를 정독한 이후로 실무에서는 VUE만 사용하다보니 손놓은지 오래되었는데 간만에 리액트를 구현할 일이 생겨 간단하게 구현했다가 애를 먹은 상황을 공유하고자 합니다.
원하는 상황은 이렇습니다.
경로 /에서 /about경로로 갈때에 지연시간을 걸어 오래동안 대기를 하는 상황을 의도적으로 만들어 대기시간을 발생시키도록 합니다.
여기서 필요한 것은 리액트에 내장되어 있는 함수인 lazy, Suspense를 사용합니다.
그럼 lazy와 Suspense가 무엇인가에 대해 알아보자
React.lazy
React.lazy는 코드를 분할하게 해줍니다. 코드 분할은 앱을 "지연 로딩"하게 도와주고 앱 사용자들에게 획기적인 성능 향상을 하게 합니다. 앱의 코드 양을 줄이지 않고도 사용자가 필요하지 않은 코드를 불러오지 않게 하며 앱의 초기화 로딩에 필요한 비용을 줄여줍니다.
예시
Before
import OtherComponent from './OtherCompnent';
After
const OtherComponent = React.lazy(() => import('./OtherComponent'));
React.lazy는 동적 import()를 호출하는 함수를 인자로 가집니다.
이 함수는 React 컴포넌트를 포함하며 default export를 가진 모듈로 결정되는 Promise로 반환해야 합니다.
lazy 컴포넌트는 반드시 Suspense 컴포넌트 하위에서 렌더링되어야 하며, Suspense는 lazy 컴포넌트가 로드되길 기다리는 동안 로딩 화면과 같은 예비 컨텐츠를 보여줄 수 있게 해줍니다.
사용 예)
import React, { Suspense } from 'react';
const OtherComponent = React.lazy(() => import('./OtherComponent'));
function MyComponent() {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<OtherComponent />
</Suspense>
</div>
);
}
Suspense
React Suspense는 구성 요소가 캐시에서 데이터를 로드하는 동안 렌더링을 일시 중단하는 일반적인 방법입니다.
즉, 화면을 구성하는 요소를 렌더링하기 전에 기다리는 순간을 조작하는 방법입니다.
쉬운 예시로 유투브와 Linkedin과 같은 곳에서 데이터를 렌더링하기 전에 사용하는 경우를 보시면 이해가실껍니다.
내가 원하는 조건대로 /에서 /about 경로로 가기전에 3분의 시간의 대기시간을 설정하고 대기시간동안에는 Loading이라는 글을 보여주는 조건을 만드는 것입니다.
Html에 보여주게 될 화면에서의 리스트 구성이다
about.js
import React from 'react';
import { Link } from 'react-router-dom';
const Menu = () => {
return (
<div>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/post">Post</Link></li>
<li><Link to="/about">About</Link></li>
<li><Link to="/about/foo">About Foo</Link></li>
<li><Link to="/detail">Detail</Link></li>
<li><Link to="/detail/view">Detail View</Link></li>
</ul>
<hr/>
</div>
);
};
export default Menu;
각 라우터에 대한 컴포넌트를 구성하는 index.js
index.js
export { default as Home } from './Home';
export { default as About } from './About';
export { default as Posts } from './Posts';
export { default as Post } from './Post';
export { default as Detail } from './detail';
export { default as DetailView } from './detailview';
about에 대한 내용을 담은 About.js
About.js
import React from 'react';
import queryString from 'query-string';
const About = ({location, match}) => {
const query = queryString.parse(location.search);
const detail = query.detail === 'true';
return (
<div>
<h2>About {match.params.name}</h2>
{detail && 'detail: blahblah'}
</div>
);
};
export default About;
lazy와 Suspense걸어 대기시간을 설정하게 하여 화면을 로딩하는 App.js
App.js
import React, { Component, Suspense, lazy } from 'react';
import { Route, Switch, Redirect } from 'react-router-dom';
import { Home, Posts, Detail, DetailView } from '../pages';
import Menu from '../components/Menu';
const About = lazy(() => {
return Promise.all([
import('../pages/About'),
new Promise(resolve => setTimeout(resolve, 180000))
])
.then(([moduleExports]) => moduleExports);
});
class App extends Component {
render() {
return (
<div>
<Suspense fallback={<div>Loading</div>}>
<Menu/>
<Route exact path="/" component={Home}/>
<Switch>
<Route path="/about/:name" component={About}/>
<Route path="/about" component={About}/>
</Switch>
<Route path="/post" component={Posts}/>
<Route path="/posts" component={Posts}/>
<Route path="/detail" component={Detail}/>
<Route path="/detail/view" component={DetailView}/>
</Suspense>
</div>
);
}
}
export default App;
우선 About.js의 import를 lazy함수를 사용하여 import 한 후 Promise를 사용하여 setTimeout을 설정하여 해당 로드를 180000(1000millisecond = 1초 -> 180000 = 180초 = 3분)을 설정합니다
그 후 렌더링 과정에서는 <Suspense></Suspense>를 영역 상위에 위치시킨뒤 fallback에 대해서는 <div>Loading</div>로 기다리는 동안 식별할 수 있도록 화면을 지정합니다.
그럼 /about을 접근하는 동안 지연이 생기게 되고 지연시간동안의 화면은 <Suspense>안의 영역은 fallback으로 지정해둔 영역으로 보이게 됩니다.
해당 예제에 대한 소스코드 레포지토리 주소입니다.
참고
https://stackoverflow.com/questions/54158994/react-suspense-lazy-delay
https://ko.reactjs.org/docs/code-splitting.html
https://runebook.dev/ko/docs/react/concurrent-mode-suspense#what-is-suspense-exactly
https://academind.com/tutorials/reactjs-a-custom-suspense-component/
'javascript > React' 카테고리의 다른 글
immer를 사용하여 더 쉽게 불변성 유지하기 (0) | 2023.01.24 |
---|---|
[React] 리액트 기초 예시 -2 (0) | 2022.07.30 |
[React] 리액트 기초 예시 - 1 (2) | 2022.07.29 |