https://mskims.github.io/redux-saga-in-korean/ ← 사가 번역 페이지
https://github.com/reactkr/learn-react-in-korean/blob/master/translated/deal-with-async-process-by-redux-saga.md ← 사가 정리 잘돼있음.
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; } }