3.리덕스 사가(Redux Saga)

5o_hyun·2023년 6월 15일
0

사용이유

redux는 무조건 동기적으로 dispatch가 이루어진다.
또한 diapatch를 여러번 할 경우 컴포넌트 파일에서 dispatch로직을 2번 써야하니 불편하기도하다.
그래서 나온 미들웨어가 redux-saga.
redux-saga는 비동기적으로 dispatch를 사용할 수 있으며(put), 내부 메소드를 활용하여, 사용자의 부주의로 인하여 동일한 api를 여러번 req할 경우 가장 최근 or 가장 마지막(takeleast) req의 res만 받아오도록 하는 기능도 있다. (thuttle, debounce)

리덕스 썽크(Redux-Thunk) vs 리덕스 사가(Redux Saga)

  • 리덕스 썽크(Redux-Thunk)
    한번에 여러번 dispatch를 할수있게해준다. 그외기능은 없어 내가 직접 구현해야함

  • 리덕스 사가(Redux Saga)
    한번에 여러번 dispatch를 할수있게해준다.
    delay후에 action실행이 가능하다.
    takeLatest 기능으로 로그인두번클릭시 썽크는 두번요청하지만, 사가는 가장 마지막 요청만 실행
    thuttle 기능으로 스크롤내릴때 1초에 몇번이상 요청이오면 나머지는 차단해줌 (셀프디도스공격막아~!!)

리덕스 사가 기본형태

import { all, fork, call, take, put } from "redux-saga/effects";

function loginAPI() {
  return axios.post("/api/post");
}

function* login() {
  try {
    const result = yield call(loginAPI);
    yield put({
      type: "LOG_IN_SUCCESS",
      data: result.data,
    });
  } catch (err) {
    yield put({
      type: "LOU_IN_FAILURE",
      data: err.response.data,
    });
  }
}

function* watchLogin() {
  yield take("LOG_IN_REQUEST", login);
}

function* watchLogout() {
  yield take("LOG_OUT_REQUEST");
}

function* watchAddPost() {
  yield take("ADD_POST_REQUEST");
}

export default function* rootSaga() {
  yield all([fork(watchLogin), fork(watchLogout), fork(watchAddPost)]);
}
/*
all : 배열을 받아 모두 동시에 실행
fork : 비동기 함수 실행 => 결과값을 안기다리고 다음거 바로 실행
call : 동시 함수 실행 => 결과값을 기다려줬다가 실행
take : action이 실행될때까지 기다리고, 실행되면 두번째인자를 실행함
put : 액션을 dispatch
*/

리덕스 사가 사용하기

1. saga 설치

npm i redux-saga

2. configureStore.js에 saga 넣기

기존 파일

import { createWrapper } from "next-redux-wrapper";
import { applyMiddleware, createStore, compose } from "redux";
import { composeWithDevTools } from "redux-devtools-extension";
import reducer from "../reducers";

const configureStore = (data) => {
  const middlewares = [];
  const enhancer =
    process.env.NODE_ENV === "production"
      ? compose(applyMiddleware(...middlewares)) // 배포용 => devtools 연결 x
      : composeWithDevTools(applyMiddleware(...middlewares)); // 개발용 => devtools 연결 o
  const store = createStore(reducer, enhancer);
  store.dispatch({
    type: "LOG_IN",
    data,
  });
  return store;
};

const wrapper = createWrapper(configureStore, {
  debug: process.env.NODE_ENV === "development",
});

export default wrapper;

수정후 파일

import { createWrapper } from "next-redux-wrapper";
import { applyMiddleware, createStore, compose } from "redux";
import { composeWithDevTools } from "redux-devtools-extension";

import reducer from "../reducers";
import rootSaga from "../sagas"; // * 사가 사용해서 추가

const loggerMiddleWare =
  ({ dispatch, getState }) =>
  (next) =>
  (action) => {
    console.log(action);
    return next(action);
  };

const configureStore = (data) => {
  const sagaMiddleWare = createSagaMiddleware(); // * 사가 사용해서 추가
  const middlewares = [sagaMiddleWare, loggerMiddleWare];
  const enhancer =
    process.env.NODE_ENV === "production"
      ? compose(applyMiddleware(...middlewares)) // 배포용 => devtools 연결 x
      : composeWithDevTools(applyMiddleware(...middlewares)); // 개발용 => devtools 연결 o
  const store = createStore(reducer, enhancer);
  store.sagaTask = sagaMiddleWare.run(rootSaga); // * 사가 사용해서 추가
  return store;
};

const wrapper = createWrapper(configureStore, {
  debug: process.env.NODE_ENV === "development",
});

export default wrapper;

2. rootSaga 만들기

// 아직 이해가 덜가서 다이해하고 수정하자.....

profile
학생 점심 좀 차려

0개의 댓글