thunk은 비동기 액션 크리에이터만 추가되고,
dispatch를 여러번 실행할 수 있다는 것이 유일한 기능이자 장점.
export const loginAction = (data) =>{
return (dispatch,getState) =>{
// getState initialState 받을 수 있음.
const state= getState();
dispatch(loginRequestAction());
axios.post('api/login')
.then((res)=>{
dispatch(loginSuccessAction(res.data));
})
.catch((err)=>{
dispatch(loginFailureAction(err))
})
}
}
// pending, fullfilled, rejected에 대한 action을 작성.
export const loginRequestAction = (data) => {
return {
type: 'LOG_IN',
data,
};
};
export const loginSuccessAction = (data) => {
return {
type: 'LOG_IN',
data,
};
};
export const loginFailureAction = (data) => {
return {
type: 'LOG_IN',
data,
};
};
// 중단점이 있는 함수. yield를 넣으면 그 부분에서 멈춤
// 중간에 함수를 멈출 수 있다는 장점이 있음.
const generator = function* rootSaga() {
console.log(1);
yield;
console.log(2);
yield;
console.log(3);
yield 4;
};
generator.next(); // 1 {value:undefined,done:false}
generator.next(); // 2 {value:undefined,done:false}
generator.next(); // 3 {value:4,done:false}
generator.next(); // {value:undefined,done:true}
--------------
// 무한반복문을 활용해서 원할 때 같은 함수(또는 객체)를 계속해서 호출할 수 있음
const gen = function* () {
while (true) {
yield 'infinite';
}
};
const g = gen();
g.next(); // {value:'infinite',done:false}
dispatch 처리 흐름
컴포넌트에서 'LOG_IN_REQUEST' 요청
saga watchLogin - login generator함수 호출
비동기 작성 성공 / 실패에 따라 dispatch 실행.
sagas/index.js
import {all, fork} from 'redux-saga/effects';
import postSaga from './post';
import userSaga from './user';
export default function* rootSaga() {
yield all([fork(postSaga), fork(userSaga)]);
}
------------------
------------------
sagas/user.js
import {all, takeLatest, delay, put, fork} from 'redux-saga/effects';
import axios from 'axios';
// api util function
function logInAPI(data) {
return axios.post('/api/login', data);
}
// logIn generator function
function* logIn(action) {
try {
const result = yield call(logInAPI, action.data);
// const result = yield fork(logInAPI, action.data);
// call : 매개변수로 주어진 함수를 동기적으로 호출함.
// fork : 매개변수로 주어진 함수를 비동기적으로 호출함.
yield put({type: 'LOG_IN_SUCCESS', data: result.data});
// put : dispatch와 동일한 용도로 사용됨.
} catch (err) {
yield put({
type: 'LOG_IN_FAILURE',
data: err.response.data,
});
}
}
function* watchLogin() {
yield takeLatest('LOG_IN_REQUEST', logIn);
// take- API는 'LOG_IN_REQUEST' 액션이 동기적으로 실행될 수 있도록 함.
// takeLatest : 연속해서(동시에) 여러 요청이 발생했을 때 마지막 요청만 실행됨. (백엔드에서 중복 데이터에 대한 관리를 해주어야 함.)
}
export default function* userSaga() {
yield all([fork(watchLogin), fork(watchLogout)]);
}
import {createWrapper} from 'next-redux-wrapper';
import reducer from '../reducers';
import {configureStore} from "@reduxjs/toolkit"
import createSagaMiddleware from 'redux-saga';
import rootSaga from '../sagas';
const sagaMiddleware = createSagaMiddleware();
const configureStore = () => {
const store = configureStore({
reducer: {reducer},
middleware:[sagaMiddleware]
});
store.sagaTask = sagaMiddleware.run(rootSaga);
return store;
};