본문 바로가기
갬발자의 프로그래밍/React

리덕스 미들웨어 알아보기

by 코라제이 2020. 1. 20.

리덕스 미들웨어를 알아보려고 한다. 액션이 리듀서로 보내지기 전에 미들웨어의 작업 설정해서 보낼 수 있다. 그러면 이 작업 들을 실행하게 되는데 리덕스로 비동기 작업을 할 때 그 효과가 크다.

 

이제 기본적인 비동기 미들웨어 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

댓글