[Redux] Reudx-Thunk 미들웨어

LMH·2022년 12월 30일
0

이번 포스팅에서는 리덕스의 비동기적인 작업의 처리하는 방법 중 Thunk 미들웨어에 대해서 정리하겠습니다.

redux-thunk

redux-thunk는 리덕스를 사용하는 프로젝트에서 비동기 작업을 처리할 대 가장 기본적으로 사용되는 미들웨어입니다. 이 라이브러리를 이해하기 위해서는 Thunk에 대해서 이해해야합니다.

thunk란?

thunk는 특정 작업을 나중에 할 수 있도록 미루기 위해 함수 형태로 감싼 것을 의미합니다.

cosnt addOne = x => x+1;
addOne(10); // 11

예시로, 전달받은 숫자에 1을 더해주는 함수가 있습니다. 이 연산작업을 미루기 위해서 thunk를 사용할 수 있습니다. 여기서, Thunk 함수는 숫자를 입력받아 addOne 함수를 호출하는 함수를 리턴하는 함수입니다.

cosnt addOne = x => x+1;
const addOneThunk = x => () => addOne(x);  // Thunk 함수는 addOne을 호출하는 함수를 리턴합니다.
}

const fn = addOneThunk(10);
setTimeout(()=> {          // 2초 후에 addOneThunk(10) 호출한 결과를 콘솔에 출력합니다.
	const value = fn();    // 최종적으로, addOne(10) 호출된 결과가 콘솔에 출력됩니다.
  	console.log(value);
}, 2000)

redux-thunk 라이브러리는 thunk 함수를 만들어서 디스패치할 수 있습니다. 그 후에 리덕스 미들웨어가 그 미들웨어가 그 함수를 전달받아 store의 dispatch와 getState를 파라미터로 넣어서 호출해 줍니다.

redux-thunk의 코드를 간단하게 나타내면 기본적으로 아래와 같습니다. 액션 객체 대신 함수를 반환합니다.

const thunk = store => next => action =>
  typeof action === 'function'
    ? action(store.dispatch, store.getState) // 액션이 함수인 경우 dispatch, getState 사용이 가능한 함수를 리턴합니다.
    : next(action)  // 액션이 함수가 아닌 경우 다음 미들웨어 또는 리듀서로 액션값을 전달합니다.

액션으로 객체가 아니라 함수가 들어올 경우에 그 함수에 store 인스턴스의 dispatch와 getState 함수를 전달하여 호출하게 됩니다. 즉, action이 함수인 경우, 함수 내부에서 dispatch, getState를 사용하여 state값을 조작하는 로직을 작성할 수 있습니다.

쉽게 접할 수 있는 예제로 클릭 시 숫자가 1씩 증가하거나 감소하는 counter를 예시로 코드를 작성하겠습니다. redux-actions 라이브러리를 이용해서 액션과 리듀서를 정의합니다.

// Counter.js
import { createAction, handleActions } from 'redux-actions';

const INCREASE = 'counter/INCREASE'
const DECREASE = 'counter/DECREASE'

export const increase =createAction(INCREASE);
export const decrease =createAction(DECREASE);

export const increaseAsync = () => dispatch => {
	setTimeout(() => {   // 1초 후에 type이 'counter/INCREASE'인 객체를 디스패치합니다.
    	dispatch(increase());
    }, 1000)
};

export const decreaseAsync = () => dispatch => {
	setTimeout(() => {   // 1초 후에 type이 'counter/DECREASE'인 객체를 디스패치합니다.
    	dispatch(decrease());
    }, 1000)
};

const initialState = 0;

const counter = handleActions(  // handleActions로 리듀서 생성합니다.
  {
    [INCREASE] : state => state + 1,
    [DECREASE] : state => state - 1
  },
  initialState
);

export default counter;

thunk 미들웨어만 존재한다는 가정하에 increaseAsync의 비동기 작업의 순서를 정리하면,

  1. 클릭과 같은 이벤트를 통해서 increaseAsync 함수를 디스패치하게 됩니다.
  2. 액션이 리듀서로 전달되기 전에 redux-thunk 미들웨어에서 increaseAsync(store.dispatch, store.getState)를 리턴합니다.
  3. 리턴과 동시에 호출된 increaseAsync(store.dispatch, store.getState)는 setTimeout에 의해 1초 뒤에increase()로 인해 생성된 객체({ type : 'counter/INCREASE' })를 디스패치 합니다.
  4. 디스패치로 전달된 액션 객체는 thunk 미들웨어로 전달지만 액션이 함수가 아니기 때문에 next 함수를 호출 시키게 됩니다.
  5. next 함수가 호출되어 액션 객체는 counter 리듀서로 전달되고 state 값이 1이 증가합니다.

정리

thunk 함수가 무엇인지와 비동기적 작업 처리 시 redux-thunk 미들웨어의 역할에 대해서 정리해보았습니다. 내용들을 정리하면서 리덕스에서 미들웨어 편의성과 작업 처리방식과 흐름에 대해 이해할 수 있게 되었습니다. 미들웨어 개념이 리덕스를 처음 사용하는 사람에게는 진입장벽이 될 수도 있겠지만 익숙해진다면 굉장히 유용한 도구가 될 것이라는 생각이 들었습니다. 다음에는 더 까다로운 상황에 적용할 수 있는 redux-saga 미들웨어에 대해서 다뤄볼까 합니다.

Reference

길벗 출판사, 리액트를 다루는 기술

profile
새로운 것을 기록하고 복습하는 공간입니다.

0개의 댓글