28일차

그루트·2021년 10월 12일
0
post-custom-banner

리덕스 미들웨어

리덕스 미들웨어는 리덕스가 지니고 있는 핵심 기능입니다. Context API 또는 MobX를 사용하는것과 차별화가 되는 부분이죠.

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

여기서 언급한 추가적인 작업들은 다음과 같은 것들이 있습니다.

  • 특정 조건에 따라 액션이 무시되게 만들 수 있습니다.
  • 액션을 콘솔에 출력하거나, 서버쪽에 로깅을 할 수 있습니다.
  • 액션이 디스패치 됐을 때 이를 수정해서 리듀서에게 전달되도록 할 수 있습니다.
  • 특정 액션이 발생했을 때 이에 기반하여 다른 액션이 발생되도록 할 수 있습니다.
  • 특정 액션이 발생했을 때 특정 자바스크립트 함수를 실행시킬 수 있습니다.

보통 리덕스에서 미들웨어를 사용하는 주된 사용 용도는 비동기 작업을 처리 할 때 입니다. 예를 들어 리액트 앱에서 우리가 만약 백엔드 API 를 연동해야 된다면, 리덕스 미들웨어를 사용하여 처리하곤 하죠.

리덕스 미들웨어는 누구든지 만들어서 사용 할 수 있습니다만, 일반적으로는 리덕스 미들에웨어 라이브러리를 설치하여 사용합니다. 비동기 작업에 관련된 미들웨어 라이브러리는 redux-thunk, redux-saga, redux-observable, redux-promise-middleware 등이 있습니다.

redux-saga와 redux-observable의 경우엔 특정 액션을 모니터링 할 수도 있으므로, 특정 액션이 디스패치됐을때 원하는 함수를 호출하거나, 또는 라우터를 통해 다른 주소로 이동하는 것이 가능합니다.

이 튜토리얼에서는 미들웨어를 사용하여 비동기작업을 처리하는 방법을 배우게 될 때, redux-thunk와 redux-saga만을 다루게 됩니다(이 두 라이브러리가 가장 많이 사용됩니다).

redux-thunk

리덕스를 사용하는 어플리케이션에서 비동기 작업을 처리 할 때 가장 기본적인 방법으로는 redux-thunk 라는 미들웨어를 사용하는것입니다. 이 미들웨어는 리덕스를 개발한 Dan Abramov 가 만든 것이며, redux 공식 매뉴얼에서도 이 미들웨어를 사용하여 비동기 작업을 다룹니다. 이를 사용하여 비동기 작업을 관리하는건 매우 직관적이고 간단합니다.

thunk 란?

thunk란, 특정 작업을 나중에 하도록 미루기 위해서 함수형태로 감싼것을 칭합니다.

예를 들어서 여러분들이 1 + 2를 지금 당장 하고싶다면 이렇게 하겠죠?

const x = 1 + 2;

이 코드가 실행되면 1 + 2 의 연산이 바로 진행됩니다.

하지만 다음과 같이 하면 어떨까요?

const foo = () => 1 + 2;

이렇게 하면, 1 + 2 의 연산이 코드가 실행 될 때 바로 이뤄지지 않고 나중에 foo() 가 호출 되어야만 이뤄집니다.

redux-thunk 는 뭘 하는 미들웨어일까?

가장 간단히 설명하자면, 이 미들웨어는 객체 대신 함수를 생성하는 액션 생성함수를 작성 할 수 있게 해줍니다. 리덕스에서는 기본적으로는 액션 객체를 디스패치합니다. 일반 액션 생성자는, 다음과 같이 파라미터를 가지고 액션 객체를 생성하는 작업만합니다:

const actionCreator = (payload) => ({action: 'ACTION', payload});

만약에 특정 액션이 몇초뒤에 실행되게 하거나, 현재 상태에 따라 아예 액션이 무시되게 하려면, 일반 액션 생성자로는 할 수가 없습니다. 하지만, redux-thunk 는 이를 가능케합니다.

우선 1초뒤 액션이 디스패치되게 하는 예제코드를 살펴보겠습니다:

const INCREMENT_COUNTER = 'INCREMENT_COUNTER';

function increment() {
  return {
    type: INCREMENT_COUNTER
  };
}

function incrementAsync() {
  return dispatch => { // dispatch 를 파라미터로 가지는 함수를 리턴합니다.
    setTimeout(() => {
      // 1 초뒤 dispatch 합니다
      dispatch(increment());
    }, 1000);
  };
}

이렇게 한다면 나중에 store.dispatch(incrementAsync()); 를 하면 INCREMENT_COUNTER 액션이 1초뒤에 디스패치됩니다.

이번엔 조건에 따라 액션을 디스패치하거나 무시하는 코드를 살펴봅시다:

function incrementIfOdd() {
  return (dispatch, getState) => {
    const { counter } = getState();

    if (counter % 2 === 0) {
      return;
    }

    dispatch(increment());
  };
}

만약에, 리턴하는 함수에서 dispatch, getState 를 파라미터로 받게 한다면 스토어의 상태에도 접근 할 수있습니다. 따라서, 현재의 스토어 상태의 값에 따라 액션이 dispatch 될 지 무시될지 정해줄 수 있는것이죠.

간단하게 정리를 하자면 redux-thunk 는 일반 액션 생성자에 날개를 달아줍니다. 보통의 액션생성자는 그냥 하나의 액션객체를 생성 할 뿐이지만 redux-thunk 를 통해 만든 액션생성자는 그 내부에서 여러가지 작업을 할 수 있습니다. 이 곳에서 네트워크 요청을 해도 무방하죠. 또한, 이 안에서 액션을 여러번 디스패치 할 수도 있습니다.

여기서 dispatch, getState 는 어디서 오는건가요?

간단합니다. redux-thunk 미들웨어에서, 전달받은 액션이 함수 형태 일 때, 그 함수에 dispatch 와 getState 를 넣어서 실행해줍니다. 실제로, 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;
profile
i'm groot
post-custom-banner

0개의 댓글