[React] redux-saga

소개?

redux-saga는 redux-thunk 다음으로 가장 많이 사용되는 라이브러리입니다.

redux-thunk의 경우엔 함수를 디스패치 할 수 있게 해주는 미들웨어였지요? redux-saga의 경우엔, 액션을 모니터링하고 있다가, 특정 액션이 발생하면 이에 따라 특정 작업을 하는 방식으로 사용합니다. 여기서 특정 작업이란, 특장 자바스크립트를 실행하는 것 일수도 있고, 다른 액션을 디스패치 하는 것 일수도 있고, 현재 상태를 불러오는 것 일수도 있습니다.

redux-saga는 redux-thunk로 못하는 다양한 작업들을 처리 할 수 있습니다.

예를 들자면..

비동기 작업을 할 때 기존 요청을 취소 처리 할 수 있습니다
특정 액션이 발생했을 때 이에 따라 다른 액션이 디스패치되게끔 하거나, 자바스크립트 코드를 실행 할 수 있습니다.
웹소켓을 사용하는 경우 Channel 이라는 기능을 사용하여 더욱 효율적으로 코드를 관리 할 수 있습니다
API 요청이 실패했을 때 재요청하는 작업을 할 수 있습니다.
이 외에도 다양한 까다로운 비동기 작업들을 redux-saga를 사용하여 처리 할 수 있답니다.

Generator 문법 배우기

제너레이터 함수를 만들 때에는 function* 이라는 키워드를 사용합니다.

제너레이터 함수를 호출했을때는 한 객체가 반환되는데요, 이를 제너레이터라고 부릅니다.

사용 예제

우리가 버튼을 눌렀을 때 원격 서버로부터 한 유저 데이터를 fetch하는 UI를 다룬다고 가정해봅시다. (간결함을 위해, 액션 실행 코드를 바로 보여드리겠습니다.)

class UserComponent extends React.Component {
  ...
  onSomeButtonClicked() {
    const { userId, dispatch } = this.props
    dispatch({type: 'USER_FETCH_REQUESTED', payload: {userId}})
  }
  ...
}

컴포넌트는 플레인 오브젝트 액션을 스토어에 dispatch 합니다. 우리는 모든 USER_FETCH_REQUESTED 액션을 지켜보면서 유저 데이터를 fetch하는 API를 호출하도록 하는 Saga를 만들 것입니다.

saga.js

import { call, put, takeEvery, takeLatest } from 'redux-saga/effects'
import Api from '...'

// worker Saga: USER_FETCH_REQUESTED 액션에 대해 호출될 것입니다
function* fetchUser(action) {
   try {
      const user = yield call(Api.fetchUser, action.payload.userId);
      yield put({type: "USER_FETCH_SUCCEEDED", user: user});
   } catch (e) {
      yield put({type: "USER_FETCH_FAILED", message: e.message});
   }
}

/*
  각각의 dispatch 된 `USER_FETCH_REQUESTED` 액션에 대해 fetchUser를 실행합니다.
  동시에 user를 fetch하는 것을 허용합니다.
*/
function* mySaga() {
  yield takeEvery("USER_FETCH_REQUESTED", fetchUser);
}

/*
  또는 takeLatest를 사용할 수 있습니다.

  동시에 user를 fetch하는 것을 허용하지 않습니다. 만약 fetch가 이미 대기 상태일 때  "USER_FETCH_REQUESTED"가 dispatch가 되었다면 대기 상태의 fetch는 취소되고 항상 최근 것만이 실행됩니다.
*/
function* mySaga() {
  yield takeLatest("USER_FETCH_REQUESTED", fetchUser);
}

export default mySaga;

Saga를 실행하기 위해서 redux-saga 미들웨어를 리덕스 스토어에 연결해야 합니다.

import { createStore, applyMiddleware } from 'redux'
import createSagaMiddleware from 'redux-saga'

import reducer from './reducers'
import mySaga from './sagas'

// saga 미들웨어를 생성합니다.
const sagaMiddleware = createSagaMiddleware()
// 스토어에 mount 합니다.
const store = createStore(
  reducer,
  applyMiddleware(sagaMiddleware)
)

// 그리고 saga를 실행합니다.
sagaMiddleware.run(mySaga)

// 애플리케이션을 render합니다.

출처 :
https://react.vlpt.us/redux-middleware/10-redux-saga.html
https://mskims.github.io/redux-saga-in-korean/

좋은 웹페이지 즐겨찾기