사가

 
 
https://blog.naver.com/jhc9639/221726835009 ← 사가랑 axios랑 연동해서 쓰는 것
 

기존

기존
FETCH_MEMO_LIST 액션 하나
리듀서에서 async & await 으로 동기처리를 쭉 했음.
 
이렇게 하지말고
비동기 처리로 각각 하자! ⇒ 사가
 

New (redux-saga)

saga
기존의 FETCH_MEMO_LIST 를 아래와 같이 3개의 비동기 액션으로 나눔
  • _REQUEST: 비동기 요청
  • _SUCCESS: 비동기 요청 성공
  • _FAILURE: 비동기 요청 실패
 

액션정의

export const FETCH_MEMO_LIST_REQUEST = "FETCH_MEMO_LIST_REQUEST" export const FETCH_MEMO_LIST_SUCCESS = "FETCH_MEMO_LIST_SUCCESS" export const FETCH_MEMO_LIST_FAILURE = "FETCH_MEMO_LIST_FAILURE"
 

액션생성함수

  • 컴포넌트에서 액션을 발생시키려고 호출하는 함수
  • 유저는 액션함수로 액션을 발생시킴. dispatch(액션생성함수)
export interface FetchMemoListAction { type: typeof types.FETCH_MEMO_LIST_REQUEST } export const fetchMemoList = (): FetchMemoListAction => ({ type: types.FETCH_MEMO_LIST_REQUEST, })
 

사가 코드

  • takeLatest()- 사가에서 제공하는 side effect 처리를 위한 함수
    • 함수는 스토어에 들어오는 액션을 보고 있다가 특정 액션만 잡아서 로직을 수행함.
  • call() - 사가에서 제공하는 side effect 처리를 위한 함수
    • 함수는 인자로 받은 함수를 실행하는데, 해당 함수가 promise를 반환하는 경우라면 promise가 처리될 때까지 generator를 중지시킴 (동기처리)
  • put()
    • 함수는 액션을 스토어로 디스패치하는 역할을 한다.
      (유저가 dispatch하면 사가가 중간에서 잡았는데, put()함수로 비로소 진짜 dispatch가 됨)
      ⇒ 스토어 상태를 갱신하는 것은 리듀서의 몫
import { takeLatest } from 'redux-saga/effects' export default function* rootSaga() { takeLatest(FETCH_MEMO_LIST_REQUEST, fetchMemoList$), } function* fetchMemoList$() { try { const memos = yield call(api.fetchMemoList) yield put({ type: FETCH_MEMO_LIST_SUCCESS, payload: memos }) } catch (err) { // 실패 로직: 나중에 작성할 것임 } }
 

리듀서

액션을 받아서 처리하는 함수 (state 갱신)
const memoReducer = (state = initialState, action: MemoActionTypes): MemoState => { switch (action.type) { // 새로 정의한 액션 타입으로 스토어 상태를 갱신한다 case types.FETCH_MEMO_LIST_SUCCESS: return { ...state, memos: action.payload.map(memo => ({ ...memo })) }
 

정리 (기존 vs 사가)

기존
액션, 액션생성함수
컴포넌트에서 dispatch(액션생성함수())
리듀서에서 액션을 switch-case로 구분해서 상태 갱신
사가
액션, 액션생성함수
컴포넌트에서 dispatch(액션생성함수())
사가에서 잡아서 따로 처리한 후 진짜 dispatch(액션생성함수()) ← New !
리듀서에서 액션을 switch-case로 구분해서 상태 갱신
//사가로 중간에 잡아서 처리하고 put()으로 리듀서에세 디스패치하는 간단한 코드 예제 import { delay, put } from 'redux-saga/effects'; // 액션 타입 ---------------------------------------------------------------- const INCREASE = 'INCREASE'; const DECREASE = 'DECREASE'; // 액션 생성 함수 ------------------------------------------------------------- export const increase = () => ({ type: INCREASE }); export const decrease = () => ({ type: DECREASE }); //사가 (제너레이터 함수) -------------------------------------------------------- function* increaseSaga() { yield delay(1000); // 1초를 기다립니다. yield put(increase()); // put은 특정 액션을 디스패치 해줍니다. } function* decreaseSaga() { yield delay(1000); // 1초를 기다립니다. yield put(decrease()); // put은 특정 액션을 디스패치 해줍니다. } //리듀서 ---------------------------------------------------------------------- // 초깃값 (상태가 객체가 아니라 그냥 숫자여도 상관 없습니다.) const initialState = 0; export default function counter(state = initialState, action) { switch (action.type) { case INCREASE: return state + 1; case DECREASE: return state - 1; default: return state; } }