4. 컨테이너 컴포넌트 만들기
그럼 이제 리덕스와 연동되어있는 컨테이너 컴포넌트를 만들어봅시다! 우리는 ViewerContainer 와 SpaceNavigatorContainer 를 만들게 됩니다.
ViewerContainer
먼저 ViewerContainer 컴포넌트를 만들어봅시다. 이 컴포넌트에서는 componentDidMount 가 발생하면 getApod API 를 호출하게 됩니다. 추가적으로, componentDidUpdate 에서 props 로 받은 date 가 바뀌게 될 때에도 API 를 호출합니다.
connect 하는 과정에서, 로딩 상태는 pender 리듀서의 pending 객체 내부의 액션 이름을 키로 가지는 값 pender.pending['apod/GET_APOD']
를 조회하면 됩니다.
그리고, redux-pender 를 통하여 전달된 프로미스는 .cancel()
을 호출하여 기존에 넣었던 프로미스가 무시되게끔 처리를 할 수 있습니다. 따라서, 요청을 하게 되면 멤버 변수 req 에 해당 프로미스를 담아두고, getApod 메소드가 다시 호출 될 때 이미 대기중인 요청이 있다면 cancel 을 호출해서 기존의 요청이 무시되도록 설정하고 새 요청을 넣습니다.
`src/containers/ViewerContainer.js
import React, { Component } from 'react';
import Viewer from 'components/Viewer';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as apodActions from 'store/modules/apod';
class ViewerContainer extends Component {
req = null
getApod = async () => {
const { ApodActions, loading, date } = this.props;
loading && this.req.cancel(); // 로딩중이라면 취소하기
try {
// this.req 에 Promise 담기
this.req = ApodActions.getApod(date || '');
await this.req; // 끝날 때 까지 대기
// console.log(this.props.url);
} catch (e) {
console.log(e);
}
}
componentDidMount() {
// 컴포넌트가 처음 나타날 때 요청
this.getApod();
}
componentDidUpdate(prevProps, prevState) {
// date 가 변경되면 요청
if(this.props.date !== prevProps.date) {
this.getApod();
}
}
render() {
const { date, url ,mediaType, loading } = this.props;
return (
<Viewer
date={date}
url={url}
mediaType={mediaType}
loading={loading}
/>
);
}
}
export default connect(
({ apod, pender }) => ({
date: apod.get('date'),
url: apod.get('url'),
mediaType: apod.get('mediaType'),
loading: pender.pending['apod/GET_APOD']
}),
(dispatch) => ({
ApodActions: bindActionCreators(apodActions, dispatch)
})
)(ViewerContainer);
다 작성하셨으면, App 컴포넌트에서 기존의 Viewer 대신 렌더링하세요.
src/App.js
import React, { Component } from 'react';
import ViewerTemplate from './ViewerTemplate';
import SpaceNavigator from 'components/SpaceNavigator';
import ViewerContainer from 'containers/ViewerContainer';
class App extends Component {
render() {
return (
<ViewerTemplate
spaceNavigator={<SpaceNavigator/>}
viewer={(
<ViewerContainer/>
)}
/>
);
}
}
export default App;
화면에 오늘의 우주 사진이 잘 나타났나요?
SpaceNavigatorContainer
자, 이제 화살표 버튼들도 제대로 작동하게끔 해줍시다! 이 부분은 꽤 간단합니다! handlePrev 함수와 handleNext 함수를 구현해서 ApodActions 안에 있는 액션 생성 함수들을 호출하여 SpaceNavigator 에게 전달해주시면 됩니다.
그 과정에서, connect 를 사용하여 date 와 maxDate 를 받아와서, 만약에 이 두 값이 동일할 경우엔 그 다음날짜로 이동하지 못하게끔 구현하세요.
src/containers/SpaceNavigatorContainer.js
import React, { Component } from 'react';
import SpaceNavigator from 'components/SpaceNavigator';
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux';
import * as apodActions from 'store/modules/apod';
class SpaceNavigatorContainer extends Component {
handlePrev = () => {
const { ApodActions } = this.props;
ApodActions.previous();
}
handleNext = () => {
const { ApodActions, date, maxDate } = this.props;
if(date === maxDate) return; // 오늘이면 여기서 스탑
ApodActions.next();
}
render() {
const { handlePrev, handleNext } = this;
return (
<SpaceNavigator
onPrev={handlePrev}
onNext={handleNext}
/>
);
}
}
export default connect(
({apod}) => ({
date: apod.get('date'),
maxDate: apod.get('maxDate')
}),
(dispatch) => ({
ApodActions: bindActionCreators(apodActions, dispatch)
})
)(SpaceNavigatorContainer);
모든게 잘 작동하나요?