1. redux-thunk vs redux-saga
thunk는 리덕스에서 비동기 작업을 처리할 때 많이 사용한다. 아래와 같이 9줄정도 되는 코드로 1만5천개정도의 git Star를 받았다.
function createThunkMiddleware(extraArgument) {
return ({ dispatch, getState }) => (next) => (action) => {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
};
}
const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;
export default thunk;
벨로퍼트님 블로그에 예제가 있으니 연습해보자.
그러나 나는 redux-thunk보다는 saga가 더 순수함수로 많은 기능을 사용할 수 있다고 하여 Redux-saga를 이용해보려고한다.
redux-thunk의 경우엔 함수를 디스패치 할 수 있게 해주는 미들웨어이고,
redux-saga의 경우엔 액션을 모니터링하고 있다가 특정 액션이 발생하면 이에 따라 특정 작업을 하는 방식으로 사용한다.
* 여기서 특정 작업이란, 특장 자바스크립트를 실행하는 것 일수도 있고, 다른 액션을 디스패치 하는 것 일수도 있고, 현재 상태를 불러오는 것 일수도 있다.
redux-saga는 redux-thunk로 못하는 다양한 작업들을 처리 할 수 있다.
예)
- 비동기 작업을 할 때 기존 요청을 취소 처리 할 수 있다 (개꿀)
- 특정 액션이 발생했을 때 이에 따라 다른 액션이 디스패치되게끔 하거나, 자바스크립트 코드를 실행 할 수 있다 (개꿀)
- 웹소켓을 사용하는 경우 Channel 이라는 기능을 사용하여 더욱 효율적으로 코드를 관리 할 수 있다 (참고)
- API 요청이 실패했을 때 재요청하는 작업을 할 수 있다 (개꿀)
2. next.js에 Redux-saga 설치
1. next.js에 redux-saga를 설치한다.
$ npm i redux-saga
2. 설치 다음에 추가로 next-redux-saga를 설치해야한다.
(check)
$ npm i next-redux-saga
3. /store/configureStore.js
import createSagaMiddleware from 'redux-saga';
import rootSaga from '../sagas';
const configureStore = () => {
//saga #1
const sagaMiddleware = createSagaMiddleware();
const middlewares = [sagaMiddleware, loggerMiddleware];
...
const enhancer = process.env.NODE_ENV === 'production'
? compose(applyMiddleware(...middlewares))
: composeWithDevTools(applyMiddleware(...middlewares))
const store = createStore(reducer, enhancer);
//saga #2
store.sagaTask = sagaMiddleware.run(rootSaga);
...
return store;
};
const wrapper = createWrapper(configureStore, {
debug: process.env.NODE_ENV === 'development'
});
export default wrapper;
4. next 공통 레이아웃 /pages/_app.js 에도 withReduxSaga를 추가해준다 (hoc)
import withReduxSaga from 'next-redux-saga';
...
export default wrapper.withRedux(withReduxSaga(Nodebird));
5. sagas폴더를 생성 후 index.js파일을 생성
generator
이 문법의 핵심 기능은 함수를 작성 할 때 함수를 특정 구간에 멈춰놓을 수도 있고, 원할 때 다시 돌아가게 할 수도 있다.
그리고 결과값을 여러번 반환 할 수도 있다.
함수 특정 구간에 멈추기 yield
yield로 함수 절대 멈추지 않게 하기 while(true)
while(true) > 보통 무한 반복 걸려서 프로그램 망가지는데 saga에서는 다르게 동작한다.
→ 특정 이벤트에 g.next()를 하게 되고 그 때 while문을 실행하게 하면 eventListener와 역할이 같다
3. redux-saga effect 알아보기
effect 종류
all, call, fork, put, take, takeEvery, takeLatest, throttle
(참고)
put
dispatch로 생각하면 된다.
takeEvery
모든 액션에 대하여 동작한다. (비동기)
takeLatest
같은 종류의 액션이 여러 번 요청된다면 가장 마지막 액션에 대해서만 동작을 실행한다. 즉 이전 액션 요청이 끝나지 않았음에도 불구하고 같은 종류의 액션이 여러 번 요청된다면 이전 요청을 취소한다. 웹페이지에서 특정 버튼을 여러 번 클릭하는 경우에 사용한다고 생각하면 된다.
take
해당 액션이 dispatch 되면 제너레이터를 next 하는 이펙트이다.
fork, call
fork와 call 모두 함수를 실행시켜주는 이펙트이다. 두 가지는 다음과 같은 차이가 있다.
→ fork는 비동기 실행을 한다.
→ call은 동기 실행을 한다. 따라서 순서대로 함수를 실행해야하는 API 요청 같은 곳에 쓰인다.
take, takeEvery, takeLatest
function* watchLogin(){
yield takeEvery('LOG_IN_REQUEST', logIn);
}
// while-take
function* watchLogOut(){
while(true){
yield take('LOG_OUT_REQUEST', logOut);
}
}
function* watchAddPost(){
yield takeLatest('ADD_POST_REQUEST', addPost);
}
take의 단점은 1회용이다.
> while(true)사용하면 됨
while문을 넣기 싫을 때는 ? takeEvery를 사용하면 된다.
while-take는 동기적으로 동작하지만 takeEvery는 비동기로 동작한다.
takeLatest는 실수로 클릭 2번했을 때 마지막 리퀘만 보내줌
> 하지만 백엔드에는 요청이 2번 되어있는 상태이기 때문에 새로고침하면 2번 한 것으로 적용됨
throttle
마지막 함수가 호출된 후 일정 시간이 지나기 전에 다시 호출되지 않도록 하는 것(특수한 경우에만 사용. 보통 takeLatest사용)
//2초동안 1번의 요청만 가능한 effect
function* watchAddPost(){
yield throttle('ADD_POST_REQUEST', addPost, 2000);
}
delay
정해놓은 시간동안 비동기적인 효과를 줌
function* logIn(action){
try{
yield delay(1000);
// const result = yield call(logInAPI, action.data);
yield put({
type: 'LOG_IN_SUCCESS',
// data: result.data
});
}
catch(err){
yield put({
type: 'LOG_IN_FAILURE',
data: err.response.data,
})
}
}
※ 참고 목록
벨로퍼트님 블로그 Redux-saga, Redux-thunk
인프런 React-Nodebird
'Dot Programming > React ∙ Next.js' 카테고리의 다른 글
[React] 불변성 관리 라이브러리 Immer사용하기 (0) | 2021.01.22 |
---|---|
[React] 더미데이터를 만들 때 필요한 Shortid, faker 라이브러리 (0) | 2021.01.20 |
AWS로 Next.js 배포하기3 (pm2) (0) | 2021.01.14 |
AWS로 Next.js 배포하기2 (aws) (0) | 2021.01.14 |
AWS로 Next.js 배포하기1 (next.config .js) (0) | 2021.01.14 |