React에서 redux-saga로 비동기 통신 ~ redux-thunk와의 비교도 ~

React에서 비동기 통신 처리 방법



Redux 미들웨어를 사용하여 구현

※ React의 컴퍼넌트내에서 처리하는 방법도 있습니다만, 컴퍼넌트와 통신 처리가 밀접하게 결합되어 컴퍼넌트의 소스가 복잡해져, 가독성이 떨어지는 등의 이유로 채용되는 케이스는 별로 없기 때문에 이 방법은 취해 없음

redux-saga와 redux-thunk의 비교



비동기 통신 처리의 대표인 redux-saga와 redux-thunk에 대해 비교해 보겠습니다.

redux-thunk





위 그림과 같이 redux-thunk를 도입하면 action creator 안에 비동기 통신 처리를 작성하거나 action creator에서 또 다른 action creator를 call할 수 있게 됩니다.

그 때문에, 본래의 redux의 아키텍쳐의 형태로부터 일탈하게 되어, 기술의 자유도가 오르고 개발자 각각이 쓰는 것으로 소스 코드의 가독성이 내려 버립니다.

redux-saga





· Action이 발행 → Dispatcher는 Store와 Saga의 스레드에 Action을 건네준다
· 비동기 처리를 Task로 등록합니다. 이 Task는 앱이 시작될 때부터 스레드처럼 실행을 기다립니다.
· Action이 전달되면 Watch Task는 그것을 잡아 Task를 실행. 실행 결과를 Action Creator에 전달

포인트는 Redux와 독립적으로 움직입니다.

또한 테스트를 쉽게 작성할 수 있습니다.


【↑ Redux-Saga 로고. Redux 로고와 독립적임을 보여줍니다]



redux-saga
redux-thunk


사이즈
14KB
352B

Github 스타 수
18,450
12,778

기술량
많은
적은

Action Creator
중첩되지 않음
중첩되기 때문에 콜백이 연속되어 가독성이 떨어집니다.


redux-saga의 구현 예



redux의 공식 샘플 counter를 개조하고 버튼을 누른 후 1 초 후에 카운트를 추가하는 비동기 처리를 구현합니다.

참고
· redux-saga official beginner tutorial
· 출처

saga를 실행하기 위해 다음을 구현합니다.
  • MiddleWare 만들기
  • 만든 Middleware를 Redux의 Store와 connect

  • 예) main.js
    import React from 'react'
    import ReactDOM from 'react-dom'
    import { createStore, applyMiddleware } from 'redux'
    import createSagaMiddleware from 'redux-saga'
    
    import Counter from './Counter'
    import reducer from './reducers'
    import { helloSaga } from './sagas'
    
    // sagaMiddlewareを作成
    const sagaMiddleware = createSagaMiddleware()
    // SagaMiddlewareをStoreとconnect
    const store = createStore(
      reducer,
      applyMiddleware(sagaMiddleware)
    )
    // SagaMiddlewareを実行
    sagaMiddleware.run(helloSaga)
    
    const action = type => store.dispatch({type})
    ・・・
    

    이쪽이 실행하는 Saga(helloSaga). SagaMiddleware 런타임에 인수에 전달
    saga.js
    export function* helloSaga() {
      console.log('Hello Sagas!')
    }
    

    비동기 통신 처리



    클릭한 후 1초 후에 1카운트하는 처리를 실행하는 버튼을 추가
    Counter.js
    const Counter = ({ value, onIncrement, onDecrement, onIncrementAsync }) =>
      <div>
        <button onClick={onIncrementAsync}>
          Increment after 1 second
        </button>
        {' '}
       ...
      </div>
    
    onIncrementAsync 를 Store의 action에 연결
    main.js
    function render() {
      ReactDOM.render(
        <Counter
          value={store.getState()}
          onIncrement={() => action('INCREMENT')}
          onDecrement={() => action('DECREMENT')}
          onIncrementAsync={() => action('INCREMENT_ASYNC')} />,
        document.getElementById('root')
      )
    }
    

    비동기 통신을 위해 Task와 TaskWatcher를 정의합니다.
    import { put, takeEvery } from 'redux-saga/effects'
    
    const delay = (ms) => new Promise(res => setTimeout(res, ms))
    
    // ...
    
    // worker Saga: 非同期のincrement taskを実行します
    export function* incrementAsync() {
      yield delay(1000) // Generatorをとめる働きをします。
      yield put({ type: 'INCREMENT' })
    }
    
    // TaskWatcher: INCREMENT_ASYNCのたびにincrementAsync taskを新たに作成します
    export function* watchIncrementAsync() {
      yield takeEvery('INCREMENT_ASYNC', incrementAsync)
    }
    

    action type이 INCREMENT_ASYNC이면 incrementAsync()를 실행합니다.

    효과 API



    put: Action Creator를 실행하여 Action을 dispatch합니다.
    그 외에도 select, join, call 등이 있습니다.
    참고 : h tps : // / 레즈 x - 가. js. 오 rg / 두 cs / 아피 /

    여러 Saga를 동시에 실행



    sagas.js
    export default function* rootSaga() {
      yield all([
        helloSaga(),
        watchIncrementAsync()
      ])
    }
    

    위에서 정의한 rootSaga를 middleware 런타임에 인수에 전달하여
    각 사가는 병렬로 실행됩니다.

    main.js
    // ...
    import rootSaga from './sagas'
    
    const sagaMiddleware = createSagaMiddleware()
    const store = ...
    sagaMiddleware.run(rootSaga)
    
    // ...
    

    요약



    redux 아키텍처를 그대로 독립한 것으로 비동기 처리를 구현할 수 있고 redux-thunk와 달리 쓰는 방법이 통일되기 때문에 redux-saga에서 비동기 처리를 구현하는 것이 좋다고 생각합니다.

    참고



    redux-saga officai doc
    redux-saga official github
    redux-saga README_ko

    redux-thunk github
    리액트!

    좋은 웹페이지 즐겨찾기