Thunk 와의 차이
Thunk의 단점
Side Effect
Blocking / Non-blocking
effect를 yield했다고 해서 middleware에서 처리가 끝날때까지 기다려주는 건 아님
blocking 예시
async function foo() {
const res = await api.fetchA();
console.log(res); // Response
}
function* fooSaga() {
const res = yield call(api.fetchA);
console.log(res);
}
non-blocking 예시
function foo() {
const promise = api.fetchA();
console.log(promise); // Promise
}
function* fooSaga() {
let task = yield fork(api.fetchA);
console.log(task);
}
Saga의 blocking / non-blocking 예시
function* saga() {
yield take(ACTION); // Blocking: will wait for the action
yield call(ApiFn, ...args); // Blocking: will wait for ApiFn
yield call(otherSaga, ...args); // Blocking: will wait for otherSaga to terminate
yield put(action); // Non-Blocking: will dispatch within internal schedular
const task = yield fork(otherSaga, ...args); // Non-Blocking: will not wait for otherSaga
yield cancel(task); // Non-Blocking: will resume immediately
// or
yield join(task); // Blocking: will wait for the task to terminate
}
Redux toolkit + Redux Saga
1) store 생성
import { configureStore } from "@reduxjs/toolkit";
import rootSaga from "./sagas/rootSaga";
import createSagaMiddleware from "@redux-saga/core";
import { createLogger } from 'redux-logger';
const logger = createLogger();
const rootReducer = combineReducers({
product: productReducer,
auth: authReducer,
});
const sagaMiddleware = createSagaMiddleware();
const store = **configureStore**({
reducer: rootReducer,
middleware: () => [sagaMiddleware, logger],
});
sagaMiddleware.run(rootSaga);
export default store;
2) slice 생성
// productSlice.js
import { createSlice } from "@reduxjs/toolkit";
const initialState = {
data: [],
};
export const productSlice = createSlice({
name: "product",
initialState,
reducers: {
getProductList: (state, action) => {
console.log("get productList");
},
searchProduct: (state, action) => {
console.log("search productList");
},
setProductList: (state, action) => {
console.log("set productList");
state.data = [...action.payload];
},
setSearchResult: (state, action) => {
console.log("set search result");
state.data = [...action.payload];
},
},
});
export const { getProductList, searchProduct } = productSlice.actions;
export const productReducer = productSlice.reducer;
// authSlice.js
import { createSlice } from '@reduxjs/toolkit';
const initialState = {
auth: {},
isLogin: false
}
export const authSlice = createSlice({
name: 'auth',
initialState,
reducers: {
login: (state, action) => {
...
},
logout: (state, action) => {
...
),
}
});
export const { login, logout } = authSlice.actions;
export const authReducer = authSlice.reducer;
3) saga 생성
// productSaga.js
import { takeEvery, takeLatest, put, take } from "redux-saga/effects";
import { createAction } from "@reduxjs/toolkit";
import axios from "axios";
const PRODUCT_LIST = createAction("product/getProductList");
const SEARCH_PRODUCT = createAction("product/searchProduct");
const SET_PRODUCT_LIST = createAction("product/setProductList");
const SET_SEARCH_RESULT = createAction("product/setSearchResult");
function* getProducts() {
const response = yield axios.get("http://localhost:3001/products");
const data = response.data;
yield put({ type: SET_PRODUCT_LIST, payload: data });
}
function* searchProducts(data) {
const response = yield axios.get(
`http://localhost:3001/products?q=${data.payload}`
);
const result = response.data;
yield put({ type: SET_SEARCH_RESULT, payload: result });
}
function* productSaga() {
yield takeEvery(PRODUCT_LIST, getProducts);
yield takeEvery(SEARCH_PRODUCT, searchProducts);
}
export default productSaga;
// authSaga.js
import { takeEvery, put } from "redux-saga/effects";
import { createAction } from "@reduxjs/toolkit";
const SIGNIN= createAction("auth/login");
const LOGOUT = createAction("auth/logout");
function* authSaga() {
yield takeEvery(SIGNIN, );
yield takeEvery(LOGOUT, );
}
export default authSaga;
// rootSaga.js
import { productSaga } from './productSaga';
import { authSaga } from './authSaga';
const rootSaga = function* () {
yield all([ productSaga(), authSaga() ]);
};
export default rootSaga