Table of Contents

Redux-Thunk를 이용한 상태관리

개요


Redux-Thunk란 Redux에서 비동기 작업을 처리할 때 사용하는 미들웨어.
액션 객체가 아닌 함수 자체를 dispatch할 수 있다는 특징이 있다.

Redux 미들웨어를 사용하면 액션이 dispatch 된 다음, 리듀서에서 해당 액션을 받아와 업데이트하기 전에 추가적인 작업을 할 수 있다.



Redux-Thunk 사용 이유


redux-thunk는 API 호출이 필요할 때 사용한다.

async / await 호출

 1export const fetchPost = () => {
 2  return async function(dispatch) {
 3    await axios.get('/api/post')
 4        .then((response) => {
 5            dispatch(getPostListSuccess(response));
 6        })
 7        .catch((error) => {
 8            dispatch(getPostListFailed(error));
 9        });
10  }
11}

Redux-thunk를 사용하지 않고 해당 코드로 action 호출 시 하단의 에러 코드가 노출된다.

action must be plain objects. Use custom middleware for async actions
→ 액션 생성함수는 오직 plain object 형태만 리턴해야 하는데, 위와 같이 비동기적인 코드에선 함수도 리턴하기 때문.



promise로 호출

1export const fetchPost = async () => {
2  const res = await axios.get('/api/post');
3  
4	return {
5		type: 'GET_POST_LIST_SUCCESS',
6		payload: res.data,
7	};
8};

액션 함수를 비동기적으로 처리를 하지 않는다면 에러는 발생하지 않지만, 데이터가 API Fetch되기 전에 액션이 리듀서에게 전달하기 때문에 data를 받아서 랜더링할 수 없다.

Promise를 사용하면 순식간에 실행된 reducer에서 ‘반환된 데이터가 아직 없다’(객체에 아무것도 없다!)라고 판단한다.


Redux-thunk 작동 원리


액션을 반환할 때 객체가 아니라 함수를 반환할 수 있게 해준다.

다른 말로 액션이 함수의 형태일 때 그 함수를 실행하고 또 실행하여 객체가 되었을 때 reducer로 dispatch 한다.

dispatch 이후에 Redux thunk가 실행된다.

⚫ action creator -> action -> dispatch -> Redux Thunk

Redux thunk에서 dispatch 된 액션이 함수인지 아닌지 판단한다.

⚫ Redux Thunk -> 함수인가? -> 아니요.(Plain Object) -> dispatch -> Reducer

⚫ Redux Thunk -> 함수인가? -> 예 -> 함수실행 -> dispatch -> 함수인가? -> 아니요(Plain Object) -> Reducer

즉, Redux-thunk가 API 요청이 끝날때까지 대기하고 반환값의 형태가 Plain Objects일 경우 이를 dispatch하는 역할을 담당한다.


Redux 적용


미들웨어 설치

1$ npm i redux-logger
2$ npm i redux-thunk
3$ npm i reudx-devtools-extension

스토어에 적용해주기 전에 라이브러리를 설치했다.

redux-thunk 뿐만 아니라 State, Props 등을 콘솔에서 보여주는 Logger, 크롬 익스텐션인 Redux-devtools 를 사용할 수 있도록 하는 composeWithDevTools 를 설치한다.

image

Logger 적용 사진


미들웨어 적용

 1import {applyMiddleware, compose, createStore} from 'redux';
 2import rootReducer from '../reducers';
 3import thunk from "redux-thunk";
 4import {createLogger} from "redux-logger/src";
 5import {composeWithDevTools} from "redux-devtools-extension";
 6
 7const logger = createLogger();
 8const middlewares = [thunk, logger];  // thunk와 logger를 미들웨어에 추가
 9
10export default function () {
11  const initialState = {};
12
13  return createStore(
14      rootReducer,
15      initialState,
16      compose(
17          composeWithDevTools(applyMiddleware(...middlewares))  //middlewares 배열을 넣어주었다.
18      )
19  );
20};

createStore 마지막 인자는 리덕스에 미들웨어를 추가할 수 있도록 도와준다.

middleware 배열에 thunk와 logger를 넣고 applyMiddleware(...middlewares) 를 사용하여 middleware 배열의 미들웨어를 사용하겠다고 명시한다.

크롬 익스텐션인 Redux-devtools를 사용하려면 applyMiddleware(..) 함수 자체를 composeWithDevTools로 감싸주면 된다.