리액트 - redux-saga 비동기 카운터 구현

정영찬·2022년 4월 27일
0

리액트

목록 보기
74/79

thunk를 사용해서 만든 비동기 카운터기능을 redux-saga를 사용해서 만들어보자.
먼저 라이브러리 설치를 진행한다.

$ yarn add redux-saga

modules/counter.js 에서 작성한 thunk 함수인 increaseAsync와 decreaseAsync 대신 redux-saga를 사용할 것이다.

먼저 액션 타입과, 액션 생성함수를 작성한다.

const INCREASE_ASYNC = 'INCREASE_ASYNC';
const DECREASE_ASYNC = 'DECREASE_ASYNC';

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

그다음 generator 함수를 작성한다. delay는 지연시간을 추가할때 사용되고, put은 원하는 명령을 디스패치 하라는 뜻이다.

function* increaseSaga() {
    yield delay(1000);
    yield put(increase());
}

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

generator 함수내부의 코드가 작동하게 하려면 takeEvery라는 effect도 사용해야한다.

import {delay, put, takeEvery } from 'redux-saga/effects';
export function* counterSaga() {
    yield takeEvery(INCREASE_ASYNC, increaseSaga)
    yield takeEvery(DECREASE_ASYNC, decreaseSaga)
}

여러가지 리듀서를 작성해서 rootreducer로 보냈던 것처럼 redux-sage또한 외부로 값을 내보내서 rootSaga를 만들어줘야 한다.

내보낸 saga 를 modules/index.js 에 작성한다.

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;

root 경로의 index.js에서 createSageMiddleware를 사용해서 Saga를 작성한다. sotre의 applyMiddleware 목록에서도 sagaMiddleware를 추가하고 sagaMiddleware.run(rootSaga)를 통해서 모듈로 작성한 saga를 불러와 사용할수 있게 된다.

import createSagaMiddleware from '@redux-saga/core';


const customHistory = createBrowserHistory();
const sagaMiddleware = createSagaMiddleware();

const store = createStore(rootReducer, composeWithDevTools(applyMiddleware(ReduxThunk.withExtraArgument({history: customHistory}),
sagaMiddleware,logger)));

const root = ReactDOM.createRoot(document.getElementById('root'));

sagaMiddleware.run(rootSaga)

root.render(
  <HistoryRouter history={customHistory}>
  <Provider store={store}>
  <App/>
  </Provider>
</HistoryRouter>
)

마지막으로 App에 카운터 컴포넌트를 추가하고 렌더링하면 된다.

function App() {
  return (
    <>
    <CounterContainer/>
    <Routes>
     <Route path="/" element={<PostListContainer/>}/>
     <Route path="/:id" element={<Postpage/>}/> 
   </Routes>
    </>
  );

}

+를 누르는 순간 increaseAsync가 호출되고 1초뒤에 increase가 호출되어서 리듀서를 통해 1이 더해진 값을 state에 추가했다.

-를 누르는 순간도 비슷하게 decreaseAsync가 호출되고 1초뒤에 increase가 호출되어서 리듀서를 통해 1이 감소한 값을 state에 추가했다.

modules/counter.js에서

yield takeEvery(INCREASE_ASYNC, increaseSaga)
yield takeEvery(DECREASE_ASYNC, decreaseSaga)

이렇게 두 saga 모두 takeEvery 라는 방식으로 했는데 여기서 decreaseSage를 takeLatest로 변경하고 실행한다음 + 와 - 를 여러번 눌러서 어떤 결과가 나오는지 살펴보자. 아래의 화면은 서로 3번 연속으로 버튼을 클릭했을때의 결과화면이다.

3번씩 클릭했으니 0이 되어야 할것 같지만 결과는 3번 더해지고 1번만 감소한 2가 되어있다.
이유는 takeLatest는 들어온 요청중 가장 나중에 들어온 요청만 수행하기 때문에 3번을 눌러도 제일 나중에 들어온 요청 하나만 수행하게 된다.

이와 반대로 takeLeading 이 있는데, 제일 먼저 들어온 요청을 수행하고 난다음 차례대로 들어온 요청을 수행하는 것이다.

-를 계속 클릭하고 있어도 멈춰있는게 아니라 제일 처음에 들어온 요청을 수행후, 지속적으로 들어오는 요청을 수행한다.

profile
개발자 꿈나무

0개의 댓글