e도서관/Redux-saga
나는 Redux-saga를 왜 쓰는가?
Heoky
2022. 1. 14. 16:06
Redux를 사용하다보니 dispatch가 동기적으로 이루어지는 것을 겪을 수 있었다.
내가 reducer에서 동작을 구현할 때, 한개의 dispatch가 성공적으로 작동할 경우 다음으로 넘어가고 싶은데 그럴때마다 설정한 state값을
불러와 상태 변화가 있을 경우 다음 dispatch를 또 실행해 주어야하는 번거로움이 있었다.
즉, dispatch를 여러번 할 때, 그만큼 dispatch를 여러번 써야했다. 그래서 비동기적으로 상태를 관리하기 위해 redux-saga를 도입했다.
redux-saga는 비동기적으로 dispatch를 할 수가 있는데 put을 통해 dispatch를 할 수 있다. 또한 내부 메서드를 통해 실수를 방지할 수 있는 기능이 있다. 예를 들자면, takeleast, thuttle 등..
redux-saga 사용전 알아야 할 선수 지식이 있다.
선수지식
generator function은 함수에 *를 붙이고 yield라는 것을 사용한다. 또한 next()를 통해 다음 yield를 호출 할 수 있다.
const gen = function* () {
console.log(1);
yield;
console.log(2);
yield;
console.log(3);
yield;
console.log(4)
}
const gener = gen()
// gener() - gener{<suspended>}
gener().next() -> 1
gener().next() -> 2
gener().next() -> 3
gener().next() -> 4
gener().next() -> undifined
react에서 saga 사용하기
1. store에 saga 넣기
// configureStore.js
import { createWrapper } from 'next-redux-wrapper';
import { applyMiddleware, compose, createStore } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import createSagaMiddleware from 'redux-saga';
import reducer from '../reducers';
import rootSaga from '../sagas';
const sagaMiddleware = createSagaMiddleware();
const loggerMiddleware =
({ dispatch, getState }) =>
(next) =>
(action) => {
console.log('loggerMiddleware(redux-thunk): ', action);
return next(action);
}; // 실헹되는 action을 console로 확인하기 위해 설정한 것
const configureStore = () => {
const enhancer =
process.env.NODE_ENV === 'production'
? compose(applyMiddleware(sagaMiddleware))
: composeWithDevTools(applyMiddleware(sagaMiddleware, loggerMiddleware));
const store = createStore(reducer, enhancer);
store.sagaTask = sagaMiddleware.run(rootSaga);
return store;
};
export const wrapper = createWrapper(configureStore, { debug: true });
2. rootSaga 만들기
// sagas/index.js
import { all, fork } from 'redux-saga/effects';
import userSaga from './user';
import postSaga from './post';
export default function* rootSaga() {
yield all([fork(userSaga), fork(postSaga)]);
}
3. saga 모듈 만들기
// sagas/user.js
import { all, fork, put, call, takeLatest, delay } from 'redux-saga/effects';
import axios from 'axios';
import {
LOGIN_REQUEST,
LOGIN_SUCCESS,
LOGIN_FAILURE,
} from '../reducers/user';
function loginAPI(data) {
return axios.get('http://localhost:3000/user/user.json', data);
}
function* login(action) {
try {
// api 통신할때는 call
const result = yield call(loginAPI, action.data);
console.log(result);
//yield delay(1000);
// 아래와 같이 api 결과를 핸들링하여 dispatch 가능
yield put({
type: LOGIN_SUCCESS,
data: action.data,
});
} catch (err) {
yield put({
type: LOGIN_FAILURE,
data: err.response.data,
});
}
}
function* watchLogin() {
yield takeLatest(LOGIN_REQUEST, login);
}
export default function* userSaga() {
yield all([fork(watchLogin)]);
}
LOGIN_REQUEST 가 실행되면 정의한 reducer의 액션인 LOGIN_REQUEST 가 반응을 한다. 즉, saga의 액션이 실행되면
reducer도 함께 실행된다.
reducer도 함께 실행된다.