하나씩 알아가기

가장 많이 사용되는 리덕스 미들웨어인 Redux-thunk는 무엇인가[리덕스 개념 정리 약간] 본문

리액트

가장 많이 사용되는 리덕스 미들웨어인 Redux-thunk는 무엇인가[리덕스 개념 정리 약간]

clearwater 2021. 1. 20. 11:03
728x90
반응형

틀린 부분이 있을 경우, 지적해 주시면 감사하겠습니다.

 

리덕스 미들웨어란 무엇인가?

리덕스 미들웨어는 디스패치 함수를 결합해서 새 디스패치 함수를 반환하는 고차함수(higher-order)입니다. 이들은 비동기 액션을 액션으로 전환합니다.

미들웨어는 함수 결합을 통해 서로 결합할 수 있습니다. 이는 액션을 로깅하거나, 라우팅과 같은 부수효과를 일으키거나, 비동기 API 호출을 일련의 동기 액션으로 바꾸는데 유용합니다.

위 그림처럼 미들웨어는 리듀서와 액션 사이에 존재하며, 액션이 디스패치 되었을 때 이를 수정하여 리듀서에 전달되도록 하는 역할을 할 수 있습니다.

type MiddlewareAPI = { dispatch: Dispatch, getState: () => State }
type Middleware = (api: MiddlewareAPI) => (next: Dispatch) => Dispatch

 

리덕스 미들웨어 중에 가장 다운로드 수가 많은 것은 Dan Abramov가 만든 Redux Thunk입니다.

function wrapper_function() {
  // this one is a "thunk" because it defers work for later:
  return function thunk() {   // it can be named, or anonymous
    console.log('do stuff now');
  };
}

wrapper_function()은 thunk()라는 함수를 반환하는 함수입니다. 자바스크립트는 first-class citizen이기 때문에 이의 특징인

  • 변수나 데이터 구조 안에 담을 수 있다
  • 파라미터로 전달할 수 있다
  • 리턴 값으로 사용할 수 있다

을 충족하기 때문에 가능합니다. 

wrapper_function()()

그리고 반환하는 함수를 실행하려면 이런식으로 호출해야합니다.

그렇다면 이것이 Redux에 어떻게 적용될까요?

먼저 Redux의 기본 개념을 복습합시다.

액션은 객체일 뿐입니다. Redux에 관한 한, 즉시 사용 가능한 작업은 일반 객체여야하며 type 속성이 있어야 합니다. 그 외에도 수행하려는 작업을 하는데 필요한 모든 것을 포함할 수 있습니다.

// 1. plain object
// 2. has a type
// 3. whatever else you want
{
  type: "USER_LOGGED_IN",
  username: "dave"
}

항상 이러한 객체를 손으로 작성하는 것은 성가신 일이기 때문에 Redux는 이러한 것들을 제거하기 위해 "액션 생성자"라는 것을 가지고 있습니다.

function userLoggedIn() {
  return {
    type: 'USER_LOGGED_IN',
    username: 'dave'
  };
}

똑같은 액션이지만 함수만 호출하면 액션을 생성할 수 있습니다(귀찮게 객체를 작성하지 않아도 됩니다). 

액션 생성자가 액션 객체 대신 그 함수를 반환할 수 있다면 좋을 것입니다. 이런식으로

function getUser() {
  return function() {
    return axios.get('/current_user');
  };
}

Redux에게 함수를 액션으로 처리할 수 있게 할 수 있을까요? 이것이 바로 redux-thunk가 하는 일입니다. 시스템을 통과하는 모든 동작을 살펴보는 미들웨어이며, 그것이 함수라면 그 함수를 호출합니다. 그게 전부입니다.

Redux가 thunk 함수에 두 개의 인자를 전달해야 합니다.

Dan Abramov의 repository에 있는 Redux Thunk 코드를 보면 이해하는 데 도움이 될 지도 모릅니다.

function createThunkMiddleware(extraArgument) {
  return ({ dispatch, getState }) => (next) => (action) => {
    if (typeof action === 'function') {
      return action(dispatch, getState, extraArgument);
    }

    return next(action);
  };
}

const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;

export default thunk;

action의 타입이 함수가 아닌 plain object라면 Redux에서 기대한대로기 때문에 next(action), 다음 액션으로 넘어가지만 함수인 경우 함수를 실행하여 plain object로 만든 다음 dispatch 합니다.

받아오는 두 가지 인자는 아래와 같습니다.

  • dispatch: 필요한 경우 새 작업을 전달할 수 있습니다
  • getState: 현재 상태에 액세스할 수 있습니다.

getState는 특정 작업을 전달하기 전에 Redux 저장소의 일부 조건을 확인할 때 사용될 수 있습니다.

function logOutUser() {
  return function(dispatch, getState) {
    return axios.post('/logout').then(function() {
      // pretend we declared an action creator
      // called 'userLoggedOut', and now we can dispatch it
      dispatch(userLoggedOut());
    });
  };
}

저는 위 코드가 문제없이 실행이 되는 것도 thunk 덕분에 함수를 바로 reducer로 넘기지 않고 미래의 특정 시점에 dispatch가 되도록 하기 때문입니다. Redux에서의 비동기 처리도 이로 인해 가능하게 됩니다.

 

참고 및 출처

redux.js.org/understanding/history-and-design/middleware

 

Middleware | Redux

History and Design > Middleware: How middleware enable adding additional capabilities to the Redux store

redux.js.org

github.com/reduxjs/redux-thunk/blob/master/src/index.js

 

reduxjs/redux-thunk

Thunk middleware for Redux. Contribute to reduxjs/redux-thunk development by creating an account on GitHub.

github.com

daveceddia.com/what-is-a-thunk/

 

What the heck is a 'thunk'?

Q: What is a ‘thunk’?

daveceddia.com

medium.com/@User3141592/understanding-the-redux-thunk-source-code-b3f8b930faf6

 

How Does Redux-Thunk Work?

The redux-thunk source code is only 14 lines long (sans test and configuration files). It’s just:

medium.com

 

728x90
반응형