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