ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Redux] Redux-thunk
    Front-End(Web)/React - 라이브러리들 2021. 2. 18. 15:40
    반응형

    🤔 Redux 의 비동기 오류

    Context API 에서 Redux 로 수정하는 토이 프로젝트를 진행하는 중이었다.

    action 생성자들을 별도파일로 제작하여 import 해서 사용중이었고, 이처럼 fetch() 로 가져온 데이터로 상태를 최신화할때 에러가 생겼다.

     

    내용은 대충, fetchList() 라는 액션 생성자에 cartList를 담았는데 이것이 객체형태로 정상적인 반환이 되지 않은 것 같다.

    또한, 대놓고 Async action에 대한 미들웨어를 사용하라고 권장하고 있다.

     

    이러한, 비동기 처리를 위한 적절한 미들웨어를 찾아보았다.


    💜 Redux-thunk 알아가기

    리덕스를 사용하는 앱에서 비동기 작업을 사용할 때, 가장 기본적인 방법으로 사용되는 것이 redux-thunk 이다.

    이 미들웨어는, 리덕스를 개발한 Dan Abramov 에 의해 만들어졌으며, 공식문서도 이 미들웨어를 통한 비동기 처리를 권장한다.

    Redux-thunk 의 장점은 직관적이고 익숙한 비동기 작업이 가능하다는 것이다.

     

    - thunk 란?

    출처: 네이버 영어사전(https://en.dict.naver.com/)

    ?????? 과연 Redux 와 '푹, 탁' 의 연결고리는 무엇일까 ㅋㅋㅋㅋㅋㅋㅋ

    thunk는 특정 작업을 나중에 하도록 미루기 위해 함수형태로 감쌌다는 의미이다. (출처:ko.wikipedia.org/wiki/%EC%8D%BD%ED%81%AC)

    const sumNow = 1 + 2;
    const sumSync = () => 1 + 2;
    // sumSync()

    이처럼, sumNow는 바로 덧셈을 진행하지만, sumSync() 함수는 호출되기 전까지 덧셈을 진행하지 않는다.

    객체가 아닌 함수를 반환하는 액션 생성자를 만들 수 있는 Redux-thunk 의 기능에 아주 어울리는 단어이지 않나 싶다.

     

    - Redux-thunk 의 역할

    위에서 얘기했듯, Redux-thunk 는 액션 생성자가 객체 대신 함수를 반환할 수 있도록 해주는 미들웨어이다.

    일반 액션 생성자는 아래처럼 받은 변수를 활용해서, 액션 객체를 반환하는 역할을 한다.

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

     

    이러한 객체 대신 함수를 반환하는 이유는, 특정 액션을 딜레이 시키거나 조건부로 취소하는 등에 있다.

    // 디스패치를 지연시키는 경우
    function incrementAsync(sec, gap) {  
      return function(dispatch) {  
        setTimeout(() => {  
          dispatch(increment(gap));  
        }, 1000);  
      }  
    }
    
    // 디스패치를 상태 조건부로 실행하는 경우
    function incrementIfOdd() {  
      return (dispatch, getState) => {  
        const { counter } = getState();  
        if (counter % 2 === 0) {  
          return;  
        }​  
        dispatch(increment());  
      };  
    }  

    * 액션 생성자 인자로 사용된 함수의 인자에 dispatch, getState를 전달하면, 스토어의 상태를 참조해서 디스패치가 가능한 것


    💜 Redux-thunk 사용하기

    - 설치

    npm install redux-thunk

     

    - 적용

    이전 포스팅의, 미들웨어나 redux-logger 적용방법과 똑같다. Store를 설정할 때, applyMiddleware() 를 사용한다.

    import { createStore, applyMiddleware } from 'redux';
    import ReduxThunk from 'redux-thunk';	// default 모듈을 받아온다.
    import reducer from './reducer';
    
    const store = createStore(reducer, applyMiddleware(ReduxThunk))
    
    export default store;

     

    * 기본 템플릿

    const thunkActionCreator = (payload) => 
      (dispatch, getState) => {
        // Code
    }

    다음과 같이, 액션 생성자를 만드는데 내부 인자로는 함수가 적용된다. 

     

    - Redux-thunk 반영 (Redux-Cart)

    // store.js
    import { applyMiddleware, createStore } from 'redux';
    import ReduxThunk from 'redux-thunk';
    import RootReducer from './Reducer';
    
    const store = createStore(
      RootReducer,
      applyMiddleware(ReduxThunk),
    );
    
    
    // app.js
      const fetchData = async () => {
        dispatch(loadStart());
        try {
          const res = await fetch(DATA_API);
          const cartList = await res.json();
          await dispatch(fetchList(cartList));	// 디스패치에 함수 적용
          dispatch(loadEnd());
        }
        catch(err) {
          alert(err);
        }
      }

    store.js 에서 applyMiddleware 를 통해 redux-thunk 를 반영한 모습이다.

    fetchData() 는 패치함수이면서, 동시에 액션 생성자가 된다. 또, thunk 덕에 하나의 생성자에서 다중 디스패치가 가능하다.

    이처럼, 인자로 함수를 받기 때문에 Async Function 를 적용했을 뿐 아니라, 내부에 try - catch 로직도 반영했다.

     

    - 단점

    Redux-thunk 는 보시다시피, 액션 생성자에 함수를 적용할 수 있다는 특징이 있다. 하지만, 이것이 한편으론 단점이 될 수 있다.

    • 로직의 일관성이 없어진다. 액션 생성자가 어떤 경우에는 액션 객체를, 어떤 경우에는 API 요청이나 비동기를 처리하게 된다.
    • 액션 생성자의 로직이 복잡해진다. 생성자는 액션 객체를 반환해서 디스패치로 전달하는 역할에 충실해야 하는데 부가로직이 붙는 것이다.

    redux-thunk를 통해, 쇼핑카트의 서버를 패치하는 Async Function 을 액션 생성자에 활용할 수 있었다.

    Redux 비동기, redux-thunk 를 공부하면 항상 단짝저럼 붙는 미들웨어가 있는데, 이것이 바로 redux-saga 이다.

    다음 포스팅에선 redux-saga에 대해 공부하고, 둘 중 더 적합한? 혹은 효율적인 미들웨어를 프로젝트 비동기 처리에 적용고자한다.

     

    [출처]

    - 이소영 님의 미디엄: medium.com/humanscape-tech/redux%EC%99%80-%EB%AF%B8%EB%93%A4%EC%9B%A8%EC%96%B4-thunk-saga-43bb012503e4

    - 벨로퍼트 님의 블로그: react.vlpt.us/redux-middleware/04-redux-thunk.html , velopert.com/3401  

    - a-tothe-z 님의 블로그: a-tothe-z.tistory.com/14

     

    반응형
Designed by Tistory.