-
[Redux] 아주 아주 간단한 redux-saga 기본개발/React 2022. 7. 11. 20:03
redux-saga는 generator 기능을 이용해서 만들어졌습니다.
간단하게만 알아볼게요.
제너레이터 생성 함수를 만들 때 function*을 이용합니다.
yield를 만나면 흐름이 멈추고, yield를 통해 반환되는 값은
제너레이터 함수에서 next()로 얻게 됩니다.
코드로 동작 방식을 확인해봅시다.
function* gen() { yield 1; yield 2; yield 3; } const generator = gen();
초기 상태는 suspended 입니다.
첫 next 함수은 제너레이터의 시작입니다.
generator.next();
yield로 반환되는 값이 value입니다. yield 1에 실행제어가 걸려 있는 상태고
next()를 호출할 때마다 다음 yield에 걸립니다.
마지막 yield까지 끝나면 done: true가 출력됩니다.
무한덧셈을 할 수 있는 제너레이터도 만들 수 있습니다.
function* infiniteAddGenerator() { let result = 0; while(true) { result += yield result; } }
next() 함수의 첫 호출은 제너레이터의 시작이므로 인수를 넣어도 반영되지 않습니다.
시작 후부터 인수를 넣으면 다음과 같이 나옵니다.
generator의 이런 기능을 기억합시다.
redux-thunk는 함수를 디스패치는 기능으로 비동기 처리를 할 수 있었는데요.
redux-saga는 제너레이터를 이용해 액션 객체를 디스패치하면서도 비동기 처리를 할 수 있습니다.
기존에 리듀서는 등록되어 있는 상태에서 redux-saga 코드를 추가합니다.
import { delay, put, takeEvery, takeLatest, takeLeading, } from 'redux-saga/effects'; const INCREASE_ASYNC = 'modules/INCREASE_ASYNC'; const DECREASE_ASYNC = 'modules/DECREASE_ASYNC'; 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()); } function* decreaseSaga() { yield delay(1000); yield put(decrease()); } // 내보내서 root saga 만들어야 함 export function* counterSaga() { // 매 호출마다 처리 yield takeEvery(INCREASE_ASYNC, increaseSaga); // 마지막에 호출된 거 하나만 처리 yield takeLatest(DECREASE_ASYNC, decreaseSaga); }
redux-saga/effects라는 곳에서 함수들을 가져오고 있습니다.
effects는 redux-saga 미들웨어에게 작업을 요청하는 함수들을 가지고 있습니다.
yield put이 disapatch와 유사합니다.
INCREASE_ASYNC나 DECREASE_ASYNC가 디스패치되면
각각 increaseSaga, decreaseSaga가 호출되면서 액션이 발생되므로
리듀서에서 각 타입에 맞게 처리가 진행됩니다.
import React from 'react'; import { useSelector, useDispatch } from 'react-redux'; import Counter from '../components/Counter'; import { increaseAsync, decreaseAsync } from '../modules/counter'; function CounterContainer() { const number = useSelector((state) => state.counter); const dispatch = useDispatch(); const onIncrease = () => dispatch(increaseAsync()); const onDecrease = () => dispatch(decreaseAsync()); return ( <Counter number={number} onDecrease={onDecrease} onIncrease={onIncrease} /> ); } export default CounterContainer;
saga 함수는 리듀서들로 root 리듀서를 만든 것과 비슷하게 작업한 후 export 합니다.
import { combineReducers } from 'redux'; import counter, { counterSaga } from './counter'; import posts from './posts'; import { all } from 'redux-saga/effects'; const rootReducer = combineReducers({ counter, posts }); export function* rootSaga() { yield all([counterSaga()]); } export default rootReducer;
index.js에서 미들웨어로 등록하면 됩니다.
import React from 'react'; import ReactDOM from 'react-dom/client'; import './index.css'; import App from './App'; import reportWebVitals from './reportWebVitals'; import { Provider } from 'react-redux'; import { legacy_createStore as createStore, applyMiddleware } from 'redux'; import rootReducer, { rootSaga } from './modules'; import logger from 'redux-logger'; import { composeWithDevTools } from 'redux-devtools-extension'; import ReduxThunk from 'redux-thunk'; import { BrowserRouter as Router } from 'react-router-dom'; import createSagaMiddleware from '@redux-saga/core'; const sagaMiddleware = createSagaMiddleware(); const store = createStore( rootReducer, composeWithDevTools(applyMiddleware(ReduxThunk, sagaMiddleware, logger)) ); sagaMiddleware.run(rootSaga); const root = ReactDOM.createRoot(document.getElementById('root')); root.render( <React.StrictMode> <Router> <Provider store={store}> <App /> </Provider> </Router> </React.StrictMode> ); reportWebVitals();
공식 예제는 공식 사이트를 참고해보세요.
'개발 > React' 카테고리의 다른 글
[ESLint] React 사용을 위한 기본적인 설정하기 (0) 2022.08.10 typesafe-actions를 이용해 모듈 리팩토링 해보기 (0) 2022.07.14 [Proxy error] Invalid options object. Dev Server has been initialized using an options object that does not match the API schema. - options.allowedHosts[0] should be a non-empty string. (0) 2022.07.11 redux-thunk react-router-dom v6 (2) 2022.07.11 [Redux] 아주 아주 간단한 리덕스 기본 개념 3 (0) 2022.07.08