본문 바로가기
FRONT-END

Redux-saga

by 지에스정 2020. 10. 8.

리덕스 사가는 리덕스의 미들웨어 개념을 이용하여 스토어에서 상태관리 중간에 비동기 로직을 넣을 수 있도록 하는 방법이다.

 

리덕스에 대해 이해하고 있다면 쉽게 리덕스 사가를 이해하고 적용할 수 있다.

 

우선 리덕스를 설치해보자

 

npm install --save redux-saga

 

우선 configureStore.js 라는 파일을 만든다.

 

스토어를 만들기 위해 리덕스 사가에 있는 함수이자 사가 미들웨어를 만드는 createSagaMiddleware() 함수를 이용한다.

 

createSagaMiddleware() 함수를 sagaMiddleware로 정의하고

 

applyMiddleware() 함수를 통해 함수를 인자로 받아 리덕스 미들웨어를 추가하고, run()함수로 rootSaga를 실행해준다.

import { createStore, applyMiddleware } from "redux"
import rootReducer from "../reducers"
import createSagaMiddleware from "redux-saga"
import rootSaga from "../sagas"

const sagaMiddleware = createSagaMiddleware()

const configureStore = () => {
  const store = createStore(rootReducer, appliyMiddleware(sagaMiddleware))

  sagaMiddleware.run(rootSaga)
  return store
}

export default configureStore

 

sagas/index.js 파일을 만들어 밑에서 만들어낼 사가를 모아 처리하는 루트 사가를 만든다.

 

fork() 함수를 통해 매개변수로 전달된 함수를 비동기적으로 실행하게 해준다.

 

여러 사가를 한번에 묶어줄 때에는 all( [fork('exSaga'), ... ]) 함수에 배열을 매개변수로 하여 이용하면 된다.

import {fork} from 'redux-saga/effects'
import exSaga from './exSaga'

export default function* rootSaga() {
  yield fork("exSaga")
}

 

비동기작업 세분화

 

사가를 사용하기 전 우선 리듀서를 작성할 예정이다. 요청 / 성공 / 실패 이 세가지로 비동기 작업을 세분화 해야 한다.

 

  • _REQUEST: 비동기 요청
  • _SUCCESS: 비동기 요청 성공
  • _FAILURE: 비동기 요청 실패

reducers/ex.js 라는 파일을 만들어 initialState로 상태를 정의한 후 위와 같은 방식으로 세가지 액션을 정의한 이후 액션 생성자를 만든다. 

 

그리고 reducer를 만든 후 비동기 요청에 따라 상태를 어떻게 받아올지 정한다.

export const initialState = {
  exLoding: false,
  exkError: null,
  exDone: false,
  ex: [],
 }

export const POST_EX_REQUEST = 'POST_EX_REQUEST'; 
export const POST_EX_SUCCESS = 'POST_EX_SUCCESS';
export const POST_EX_FAILURE = 'POST_EX_FAILURE';

export const exAction = () => {
  return {
    type: POST_EX_REQUEST,
  };
};

const reducer = (state = initialState, action) => {
  switch (action.type) {
      case POST_EX_REQUEST:
      return {
        ...state,
        exLoading: true,
        exDone: false,
        exError: null,
      };
    case POST_EX_SUCCESS:
      return {
        ...state,
        exLoading: false,
        exADone: true,
        ex: action.data,
      };
    case POST_EX_FAILURE:
      return {
        ...state,
        exoading: false,
        exError: action.error,
      };
      default:
      return state;
  }
};

export default reducer;

 

그러고 난 이후 reducers/rootReducer.js 파일을 만들어 루트 리듀서를 만든 후 (여러 reducer를 만들어 사용하고자 한다면)

 

사용하고자 하는 리듀서들을 combineReducers() 함수를 통해  reducer를 합쳐준다.

import {combineReducers} from 'redux';
import ex from './ex';


const rootReducer = combineReducers({
  ex,
});

export default rootReducer;

 

이제 본격적으로 사가를 사용해보자. 우선 saga/exSaga.js 파일 만들고 액션들을 import한다.

 

call()함수는 인자로 받은 함수를 실행해주는 역할을 하는데, 이번 포스팅에서는 API 데이터를 받아오기 위해서 axios를 사용하였다.

 

postEX라는 제너레이터를 만들어준다.

 

put() 함수는 액션을 스토어로 디스패치하는 역할을 하는데, POST_EX_SUCCESS와 POST_EX_FAILURE을 액션으로 발행하도록 한다. 

 

그리고 사이드 이팩트를 다루는 takeLatest() 함수를 통해 스토어에 들어오는 액션을 보고 있다가

 

postEX 액션만 잡아서 로직을 수행하도록 만들어 준다.

 

exSaga를 만들어주면 , exSaga가 rootSaga로 받아 처리하게 된다.

 

(saga를 여러개 작성할 때 사용하고, 그게 아니면 rootSaga로 따로 받아 사용하지 않아도 된다.)

 

import axios from 'axios';
import {
  POST_EX_REQUEST,
  POST_EX_SUCCESS,
  POST_EX_FAILURE,
} from '../reducers/ex';
import {fork, call, put, takeLatest} from 'redux-saga/effects';


function postExAPI(data) {
  return axios.post('api주소', data);
}

function* postEx(action) {
  try {
    yield put({
      type: POST_EX_SUCCESS,
      data: action.data,
    });
  } catch (err) {
    console.log(err);
    yield put({
      type: POST_EX_FAILURE,
      error: err.response.data,
    });
  }
}


function* watchPostEx() {
  yield takeLatest(POST_EX_REQUEST, postEx);
}


export default function* exSaga() {
  yield fork(watchPostEx)
    
}

 

리덕스에서 비동기적으로 상태를 관리하기 좋은 리덕스 사가에 대해 알아 보았다.

 

리덕스와 달리 액션 타입을 요청 / 성공 / 실패로 나누어 리듀서와 사가를 이용하여 비동기적 상태 관리의 편의성을 높여준다.

 

 

'FRONT-END' 카테고리의 다른 글

Vue.js 시작하기  (0) 2021.03.06
[React native / android]맥(Mac)에서 개발 환경 설정  (0) 2020.12.15
[React Native]expo-cli 시작하기  (0) 2020.07.18
[Material-ui] 시작하기  (0) 2020.07.06
[Redux] 리액트 - 리덕스 적용  (0) 2020.07.02