Skip to main content

redux-saga는 왜 써야하는거지?

redux-saga는 액션 생성자에서 직접 async/await을 사용하지 않고 비동기작업을 처리하기 위해 사용하는 미들웨어 라이브러리이다.

redux-saga를 사용하는 주요 이유는

액션 생성자에서 직접 async/await을 사용하는 것을 피하기 위함이다.

async/await을 사용하면 블로킹 동작을 도입하게 돼서 애플리케이션 흐름을 관리하고 테스트를 어렵게 만들 수 있음

// redux-saga를 사용하지 않음

const fetchData = async () => {
try {
const response = await fetch("https://api.example.com/data");
const data = await response.json();
return { type: "FETCH_SUCCESS", payload: data };
} catch (error) {
return { type: "FETCH_ERROR", payload: error };
}
};
// redux-saga를 사용함

import { call, put, takeEvery } from "redux-saga/effects";

function* fetchData() {
try {
const response = yield call(fetch, "https://api.example.com/data");
const data = yield response.json();
yield put({ type: "FETCH_SUCCESS", payload: data });
} catch (error) {
yield put({ type: "FETCH_ERROR", payload: error });
}
}

function* watchFetchData() {
yield takeEvery("FETCH_DATA", fetchData);
}

뿐만 아니라 redux-saga에서는 완료되기 전 새로운 액션이 발생하면 이전 액션을 cancel할 수 있다

import "babel-polyfill";
import { call, put } from "redux-saga/effects";
import { delay, takeEvery, takeLatest } from "redux-saga";
import { tick, START, TICK, STOP } from "./actions";

const ONE_SECOND = 1000;

export function* timerTickWorkerSaga(getState) {
yield call(delay, ONE_SECOND);
yield put(tick());
}

export default function* timerTickSaga() {
const workerTask = yield takeEvery([START, TICK], timerTickWorkerSaga);
yield takeLatest(STOP, cancelWorkerSaga, workerTask);
}

function* cancelWorkerSaga(task) {
yield cancel(task);
}
  • takeLatest
    • 실수로 여러번 클릭한 경우 앞에 클릭은 무시되고 마지막 클릭만 실행(제일 많이 사용함)응답을 취소함(요청 취소는 아님)
    • 2개를 요청한 경우 2개의 데이터가 저장되기에 게시글 추가인 경우 새로고침시에 똑같은 글 2개가 뜰것임
      • 이를 해결해기 위해 throttle을 사용(마지막 함수가 호출된 후 일정 시간이 지나기 전에 다시 호출되지 않도록 함)
  • takeEvery
    • 모든 클릭이 실행됨
  • takeLeading
    • 첫번째 클릭만 실행