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; } }