Redux Saga

목차

Redux Saga

액션을 모니터링하고 있다가 특정 Action 이 발생하면 특정 작업을 진행한다.

  • 비동기 작업을 진행할 때 기존 요청을 취소 할 수 있다.
  • 특정 Action 이 발생했을 때 다른 액션을 디스패치 하거나 자바스크립트 코드를 실행할 수 있다.
  • Generator 에 기반한 미들웨어

Generator

함수의 흐름을 특정 구간에 멈춰 놨다가 다시 실행 할 수 있다.
return 값을 여러번 보낼 수 있다.

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

const SET_DIFF = "counter/SET_DIFF";
const INCREASE = "counter/INCREASE";
const DECREASE = "counter/DECREASE";
const INCREASE_ASYNC = "NCREASE_ASYNC";
const DECREASE_ASYNC = "DECREASE_ASYNC";

export const setDiff = (diff) => ({ type: SET_DIFF, diff });
export const increase = () => ({ type: INCREASE });
export const decrease = () => ({ type: DECREASE });

export const increaseAsync = () => ({ type: INCREASE_ASYNC });
export const decreaseAsync = () => ({ type: DECREASE_ASYNC });

function* increaseSaga() {
yield delay(1000);
yield put(increase()); // put 은 dispatch 와 비슷한 개념
}

function* decreaseSaga() {
yield delay(1000);
yield put(decrease());
}

export function* counterSaga() {
yield takeEvery(INCREASE_ASYNC, increaseSaga);
yield takeLatest(DECREASE_ASYNC, decreaseSaga);
}

const initialState = {
number: 0,
diff: 1,
};

export default function counter(state = initialState, action) {
switch (action.type) {
case SET_DIFF:
return {
...state,
diff: action.diff,
};
case INCREASE:
return {
...state,
number: state.number + state.diff,
};
case DECREASE:
return {
...state,
number: state.number - state.diff,
};
default:
return state;
}
}
import React from "react";
import { useSelector, useDispatch } from "react-redux";
import Counter from "./Counter";
import {
increase,
decrease,
setDiff,
increaseAsync,
decreaseAsync,
} from "../modules/counter";

const CounterContainer = () => {
const { number, diff } = useSelector((state) => ({
number: state.counter.number,
}));

const dispatch = useDispatch();
// const onIncrease = () => dispatch(increase());
// const onDecrease = () => dispatch(decrease());
const onIncrease = () => dispatch(increaseAsync());
const onDecrease = () => dispatch(decreaseAsync());
const onSetDiff = (diff) => dispatch(setDiff(diff));

return (
<Counter
number={number}
diff={diff}
onIncrease={onIncrease}
onDecrease={onDecrease}
onSetDiff={onSetDiff}
/>
);
};

export default CounterContainer;
import { combineReducers } from "redux";
import counter, { counterSaga } from "./counter";
import todos from "./todos";
import { all } from "redux-saga/effects";

const rootReducer = combineReducers({
counter,
todos,
});

export function* rootSaga() {
yield all([counterSaga()]); // all 은 배열 안의 여러 사가를 동시에 실행시켜줍니다.
}

export default rootReducer;
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { createStore, applyMiddleware } from 'redux';
import rootReducer, { rootSaga } from './modules';
import { Provider } from 'react-redux';
import myLogger from './middlewares/myLogger';
import createSagaMiddleware from 'redux-saga';

const sagaMiddleware = createSagaMiddleware();
const store = createStore(rootReducer, applyMiddleware(sagaMiddleware, myLogger));

sagaMiddleware.run(rootSaga);

ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);

reportWebVitals();
Share