redux-saga는 Redux Saga는 Redux와 함께 사용되는 미들웨어 라이브러리로, 비동기 작업을 관리
Redux Saga에서 사용되는 제너레이터(Generator) 함수를 사용하여 비동기 작업을 동기적으로 다룰 수 있는 방식을 제공, 액션들 간의 순서를 조절하고 상태 변화를 관리할 수 있다.
즉, ⇒ axios요청같이 데이터를 가져오는 비동기 동작이나 브라우저의 캐시에 접근하는 그런 사이드 이펙트들을 관리할 수 있게 해주는 도구
이러한 원리로 액션을 감지하고, 특정 액션이 발생했을때 우리가 원하는 자바스크립트 코드를 실행시켜줌.
import { createStore, combineReducers, compose, applyMiddleware } from "redux";
import { persistStore, persistReducer } from "redux-persist";
import storage from "redux-persist/lib/storage";
import { reducer as dataReducer } from "./reducer";
import createSagaMiddleware from "redux-saga";
import rootSaga from "./sagas/rootSaga";
const persistConfig = {
key: "",
storage,
whitelist: [],
};
const persistedReducer = persistReducer(persistConfig, dataReducer);
const devTools =
process.env.NODE_ENV !== "production" &&
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
: null;
const composeEnhancers = devTools || compose;
const appReducer = combineReducers({
data: persistedReducer,
});
// sagaMiddleware 선언(미들웨어로 사용)
export const sagaMiddleware = createSagaMiddleware();
const enhancer = composeEnhancers(applyMiddleware(sagaMiddleware));
// redux의 store 생성, 리듀서와 미들웨어 사용
export const store = createStore(appReducer, enhancer);
export const persistor = persistStore(store);
sagaMiddleware.run(rootSaga);
리덕스 사가(Redux Saga)에서 제공하는 createSagaMiddleware API를 사용하면 사가 미들웨어(Saga Middleware)를 생성.
그리고 생성된 사가 미들웨어는 리덕스(Redux)에서 제공는 applyMiddleware API를 호출할 때 인자로 넘겨 리덕스 미들웨어(Redux Middleware)로 추가
사가 미들웨어(Saga Middleware)의 run 메서드를 통해 사가(Saga)를 실행
rootSaga는 제네레이터 함수(function *)을 담은 사가!
function* 무엇일까?
함수의 코드 블록을 한 번에 실행하지 않고 함수 코드 블록의 실행을 일시 중지했다가 필요한 시점에 재시작할 수 있는 함수이고 yield 키워드를 사용하여 제너레이터 함수 내에서 값을 생성하거나 값을 반환하며 함수의 실행을 일시 중단할 수 있다.
yeild는 무엇일까?
yield를 사용하여 비동기 작업(예: API 호출 등)을 순차적으로 실행할 수 있다. 제너레이터 함수 내에서 yield 키워드를 만나면 해당 작업이 완료될 때까지 함수 실행이 중단되며, 그 후에 다음 작업으로 이동한다.
Redux-Saga에는 function* 사용되는 헬퍼함수(effect)가 있다.
다들 아시겠지만, 비유를 들자면
당신은 그룹 내에서 주방에서 요리를 준비하고 있다.. 각 사람이 식사를 기다리고 있으며, 요리가 완성되기를 기다린다. 요리가 완료되면 각 사람에게 식사를 제공하고, 그 다음 사람들은 식사를 마칠 때까지 기다림. 함수 호출(call)이 완료될 때까지 기다리며, 다음 코드 실행은 블록.
당신은 그룹 내에서 여러 요리를 동시에 준비하고 있다. 각 요리사는 독립적으로 요리를 하며, 한 요리가 완료되어도 나머지 요리는 계속 진행된다. 각 요리가 완료되면 각자의 식사를 받고 먹기 시작함. 함수 호출(fork)이 블록되지 않고 바로 다음 코드로 진행. 호출된 함수의 실행은 독립적으로 진행된다.
yield put({
type: 'LOG_IN_SUCCESS',
data: result.data
});
이런식으로 말이다.
ex) const A = yield select(state ⇒ state.~~)
(redux useselct와 같음)
import axios from 'axios';
import {all, call, fork, put, takeLatest} from 'redux-saga/effects';
import { SwpLogRes } from '../actions/LogAction';
import { LogType } from '../constants/actionType';
import React from 'react';
axios.defaults.baseURL = 'http://localhost:8070';
function logReq() {
const result = axios
.get('/api/logs/log.log')
.then((res) => {
console.log('[LOG] Log 통신 성공');
return res.data;
})
.catch((err) => {
console.log('[LOG] Log 통신 에러');
return err;
});
return result;
}
function* postSwpLogReq() {
try {
const logs = yield call(logReq);
yield put(SwpLogRes(logs + <br />));
} catch (e) {
console.log(e);
}
}
function* watchAlert() {
yield takeLatest(LogType.LOG_REQ, postSwpLogReq);
}
다음은 제네레이터 함수를 사용한 saga통신이다.
redux-saga
를 사용하면 코드의 복잡성이 증가.
Such a good post.