리덕스 미들웨어를 알아보려고 한다. 액션이 리듀서로 보내지기 전에 미들웨어의 작업 설정해서 보낼 수 있다. 그러면 이 작업 들을 실행하게 되는데 리덕스로 비동기 작업을 할 때 그 효과가 크다.
이제 기본적인 비동기 미들웨어 thunk를 알아보자.
thunk를 설치한다.
$ yarn add redux-thunk
전에 만들었던 MovieRankAPI 를 복사해서 MovieMiddleware로 만들어 본다.
lib폴더를 만들고 api 파일을 만든다 (앞에서 영화 api를 가져오는 주소)
import axios from "axios";
export const getBoxOffice = query =>
axios.get(
`http://www.kobis.or.kr/kobisopenapi/webservice/rest/boxoffice/searchDailyBoxOfficeList.json?key=제공받은키=${query}`
);
모듈에 movie.js 를 만든다.
import * as api from "../lib/api";
const GET_BOXOFFICE = "movie/GET_BOXOFFICE";
const GET_BOXOFFICE_SUCCESS = "movie/GET_BOXOFFICE_SUCCESS";
const GET_BOXOFFICE_FAILURE = "movie/GET_BOXOFFICE_FAILURE";
const initialState = {
movie: null,
loading: {
GET_BOXOFFICE: false
}
};
export const getBoxOffice = date => async dispatch => {
dispatch({ type: GET_BOXOFFICE });
try {
const res = await api.getBoxOffice(date);
dispatch({
type: GET_BOXOFFICE_SUCCESS,
payload: res.data.boxOfficeResult.dailyBoxOfficeList
});
} catch (e) {
dispatch({
type: GET_BOXOFFICE_FAILURE,
error: true,
payload: e
});
throw e;
}
};
const movie = (state = initialState, action) => {
switch (action.type) {
case GET_BOXOFFICE:
return {
...state,
loading: {
GET_BOXOFFICE: true
}
};
case GET_BOXOFFICE_SUCCESS:
return {
movie: action.payload,
loading: {
GET_BOXOFFICE: false
}
};
case GET_BOXOFFICE_FAILURE:
return {
movie: action.payload,
loading: {
GET_BOXOFFICE: false
}
};
default:
return state;
}
};
export default movie;
getBoxOffice는 thunk 함수이다. 여기서 비동기 작업을 액션을 각각 작업할 수 있다.
이제 컨테이너를 만든다.
import React from "react";
import { connect } from "react-redux";
import MovieList from "../components/MovieMiddleware/MovieList";
import { getBoxOffice } from "../modules/movie";
const { useEffect } = React;
const MovieContainer = ({ getBoxOffice, boxoffice, loading }) => {
useEffect(() => {
getBoxOffice("20190101");
}, [getBoxOffice]);
return (
<>
<MovieList
movie={boxoffice}
loading={loading}
getBoxOffice={getBoxOffice}
/>
</>
);
};
export default connect(
({ movie }) => ({
boxoffice: movie.movie,
loading: movie.loading.GET_BOXOFFICE
}),
{
getBoxOffice
}
)(MovieContainer);
앞에서 한 리덕스와 똑같다. 다만 처음 마운트 될 때 보이는 화면이 필요하기 때문에 useEffect를 사용했다.
마지막으로 MovieMiddleware의 MovieList를 바꿔준다.
import React, { useState, useEffect, useCallback, useRef } from "react";
import MovieItem from "./MovieItem";
import styled from "styled-components";
const ListBlock = styled.div`
margin: 0 auto;
margin-top: 100px;
width: 768px;
@media screen and (max-width: 768px) {
width: 100%;
}
& > div {
margin: 0 auto;
width: 450px;
}
.fdiv {
border-radius: 6px;
background: rgb(101, 173, 255);
display: flex;
align-items: center;
justify-content: center;
height: 5rem;
font-weight: 600;
font-size: 2rem;
color: white;
}
.date {
display: flex;
width: 450px;
background: white;
}
.input {
flex: 1;
text-align: center;
}
`;
const MovieList = ({ loading, movie, getBoxOffice }) => {
const [value, setvalue] = useState("");
const focus = useRef(null);
const onChange = useCallback(
e => {
setvalue(e.target.value);
},
[]
);
const onSubmit = useCallback(
e => {
e.preventDefault();
const num = parseInt(value);
if (!value || !num || value.length !== 8) return;
setvalue("");
getBoxOffice(value);
focus.current.focus();
},
[value]
);
return (
<ListBlock>
<div>
<div className="fdiv">영화순위</div>
<form className="date" onSubmit={onSubmit}>
<input
className="input"
value={value}
onChange={onChange}
ref={focus}
placeholder=" 궁금한 날 예) 20190105 처럼 입력"
/>
<button>검색</button>
</form>
{loading && "로딩중"}
{!loading &&
movie &&
movie.map(movie => <MovieItem key={movie.rank} movie={movie} />)}
</div>
</ListBlock>
);
};
export default MovieList;
결과가 잘 나온다.
'갬발자의 프로그래밍 > React' 카테고리의 다른 글
리덕스 에러상황 (0) | 2020.02.11 |
---|---|
리액트 에러 상황 (1) | 2020.01.28 |
REDUX 알아보기 (0) | 2020.01.16 |
영화 API 사용해보기 (0) | 2020.01.15 |
리액트 라우터 사용하기 (0) | 2020.01.15 |
댓글