Redux Saga ํบ์๋ณด๊ธฐ! ๐งโ๏ธ
Redux Saga๋ Redux์์ ๋น๋๊ธฐ ์์ ์ ๊น๋ํ๊ณ ์ฐ์ํ๊ฒ ์ฒ๋ฆฌํ๊ธฐ ์ํ ๋ฏธ๋ค์จ์ด์์. ์ด๋ฆ๋ถํฐ ๋ญ๊ฐ ์ค์ผ์ผ์ด ์ปค ๋ณด์ด์ง ์๋์? “์ฌ๊ฐ(Saga)“๋ ์ฐ๋๊ธฐ๋ผ๋ ๋ป์ธ๋ฐ, ๋น๋๊ธฐ ์์ ์ ์ด์ผ๊ธฐ์ฒ๋ผ ์ ์ง์ฌ์ง ํ๋ฆ์ผ๋ก ๊ด๋ฆฌํ๊ฒ ๋ค! ๋ผ๋ ํฌ๋ถ๋ฅผ ๋ด๊ณ ์์ต๋๋ค. ์ค๋์ Redux Saga๊ฐ ์ ํ์ํ์ง, ์ด๋ป๊ฒ ์ฌ์ฉํ๋์ง, ๊ทธ๋ฆฌ๊ณ ์ด๋ค ๋งค๋ ฅ์ด ์๋์ง ๋ค๋ค๋ณผ๊ฒ์. ๐
โฒ๏ธ Redux Saga๋ ์ ํ์ํ๊ฐ์?
์ฐ๋ฆฌ๊ฐ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฐ๋ฐํ๋ค ๋ณด๋ฉด ์ด๋ฐ ์ํฉ๊ณผ ๋ง์ฃผํ๊ฒ ๋ผ์:
- ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๊ธฐ ์ํด API ํธ์ถ์ ํด์ผ ํ๋ค.
- ํธ์ถ ์ค์ ๋ก๋ฉ ์ํ๋ฅผ ๋ณด์ฌ์ฃผ๊ณ , ์๋ฌ๊ฐ ๋๋ฉด ๋ฉ์์ง๋ ๋์์ผ ํ๋ค.
- ์์ฒญ์ด ๋๋๋ฉด ์ฑ๊ณต ์ฌ๋ถ์ ๋ฐ๋ผ ๋ค๋ฅธ ์์ ์ ์ฒ๋ฆฌํด์ผ ํ๋ค.
๋น๋๊ธฐ ์์ ์ ์ฒ๋ฆฌํ๊ธฐ ์ํด Redux Thunk ๊ฐ์ ๋๊ตฌ๋ ์์ง๋ง, ๋ณต์กํ ๋น๋๊ธฐ ํ๋ฆ์ ๋ค๋ฃฐ ๋ ์ฝ๋๊ฐ ์ ์ ๊ธธ์ด์ง๊ณ ์์ผ๋ฒ๋ฆด ์ ์์ด์.
Redux Saga๋ ์ ๋๋ ์ดํฐ ํจ์์ ์ดํํธ๋ฅผ ์ฌ์ฉํด ๋น๋๊ธฐ ๋ก์ง์ ๊น๋ํ๊ฒ ๊ตฌ์ฑํ ์ ์๋๋ก ๋์์ค์.
๐ Redux Saga์ ํต์ฌ ๊ฐ๋
์ ๋๋ ์ดํฐ ํจ์๋?
Redux Saga์ ํต์ฌ์ ์ ๋๋ ์ดํฐ ํจ์์ ๋๋ค.
์ ๋๋ ์ดํฐ๋ function*์ผ๋ก ์ ์ธํ๋ฉฐ, yield ํค์๋๋ฅผ ์ฌ์ฉํด ํจ์ ์คํ์ ์ ์ ๋ฉ์ถ ์ ์์ด์.
function* generatorExample() {
console.log("Start");
yield "Pause 1";
console.log("Middle");
yield "Pause 2";
console.log("End");
}
์ ๋๋ ์ดํฐ๋ฅผ ์คํํ๋ฉด ํจ์๊ฐ ํ ๋จ๊ณ์ฉ ๋ฉ์ถ๋ฉฐ ์งํ๋ฉ๋๋ค. Redux Saga๋ ์ด “๋ฉ์ถ๊ณ ์คํ”์ ํน์ฑ์ ํ์ฉํด ๋น๋๊ธฐ ์์ ์ ๊ด๋ฆฌํฉ๋๋ค.
๐๏ธ Redux Saga ์ค์นํ๊ธฐ
๋จผ์ ํจํค์ง๋ฅผ ์ค์นํด์ผ๊ฒ ์ฃ ?
npm install redux-saga
๐ก Redux Saga ๊ธฐ๋ณธ ์ฌ์ฉ๋ฒ
Redux Saga๋ฅผ ์ ๋๋ก ํ์ฉํ๋ ค๋ฉด ์ฌ๊ฐ(Saga)๋ฅผ ์์ฑํ๊ณ , ๋ฏธ๋ค์จ์ด๋ก ๋ฑ๋กํด์ผ ํด์.
1๏ธโฃ ์ฌ๊ฐ ์์ฑํ๊ธฐ
import { takeEvery, put, call } from "redux-saga/effects";
// 1. ๋น๋๊ธฐ ์์
ํจ์
function* fetchDataSaga() {
try {
const response = yield call(fetch, "https://jsonplaceholder.typicode.com/posts");
const data = yield response.json();
yield put({ type: "FETCH_SUCCESS", payload: data });
} catch (error) {
yield put({ type: "FETCH_FAILURE", error });
}
}
// 2. ๊ฐ์์ ์ฌ๊ฐ
function* watchFetchData() {
yield takeEvery("FETCH_REQUEST", fetchDataSaga);
}
export default watchFetchData;
2๏ธโฃ ์ฌ๊ฐ ๋ฏธ๋ค์จ์ด ๋ฑ๋กํ๊ธฐ
์ด์ Redux ์คํ ์ด์ Redux Saga ๋ฏธ๋ค์จ์ด๋ฅผ ์ถ๊ฐํฉ๋๋ค.
import { createStore, applyMiddleware } from "redux";
import createSagaMiddleware from "redux-saga";
import rootReducer from "./reducers";
import rootSaga from "./sagas";
const sagaMiddleware = createSagaMiddleware();
const store = createStore(rootReducer, applyMiddleware(sagaMiddleware));
// ์ฌ๊ฐ ์คํ
sagaMiddleware.run(rootSaga);
export default store;
๐ Redux Saga์ ์ฃผ์ ์ดํํธ
Redux Saga๋ ๋น๋๊ธฐ ์์ ์ ์ํด ๋ค์ํ ์ดํํธ(Effects)๋ฅผ ์ ๊ณตํฉ๋๋ค. ์ด ์ดํํธ๋ ์ฌ๊ฐ ๋ด๋ถ์์ ์ฌ์ฉํ๋ ํน๋ณํ ๋ช ๋ น์ด ๊ฐ์ ๊ฑฐ์์!
๐ call(fn, ...args)
๋น๋๊ธฐ ํจ์๋ฅผ ํธ์ถํฉ๋๋ค. fetch๋ axios ๊ฐ์ ๋น๋๊ธฐ ํจ์ ํธ์ถ์ ์ฌ์ฉ๋ผ์.
const data = yield call(api.fetchUser, userId);
๐ put(action)
Redux ์คํ ์ด์ ์ก์ ์ ๋์คํจ์นํฉ๋๋ค.
yield put({ type: "FETCH_SUCCESS", payload: data });
๐ takeEvery(actionType, saga)
ํน์ ์ก์ ์ด ๋ฐ์ํ ๋๋ง๋ค ์ง์ ํ ์ฌ๊ฐ๋ฅผ ์คํํฉ๋๋ค.
yield takeEvery("FETCH_REQUEST", fetchDataSaga);
๐ takeLatest(actionType, saga)
๋ง์ง๋ง์ผ๋ก ๋ฐ์ํ ์ก์ ๋ง ์ฒ๋ฆฌํฉ๋๋ค. ์ด์ ์์ฒญ์ ๋ฌด์๋ผ์.
yield takeLatest("FETCH_REQUEST", fetchDataSaga);
๐ select(selector)
ํ์ฌ ์ํ๋ฅผ ์ ํ(select)ํฉ๋๋ค.
const user = yield select((state) => state.user);
๐ฉ๐ป๐ป ์ค์ ์์ : ์ฌ์ฉ์ ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ
์ก์ ์์ฑ์
export const fetchUserRequest = () => ({ type: "FETCH_USER_REQUEST" });
๋ฆฌ๋์
const initialState = {
loading: false,
user: null,
error: null,
};
function userReducer(state = initialState, action) {
switch (action.type) {
case "FETCH_USER_REQUEST":
return { ...state, loading: true };
case "FETCH_USER_SUCCESS":
return { ...state, loading: false, user: action.payload };
case "FETCH_USER_FAILURE":
return { ...state, loading: false, error: action.error };
default:
return state;
}
}
export default userReducer;
์ฌ๊ฐ
import { takeEvery, call, put } from "redux-saga/effects";
function* fetchUserSaga() {
try {
const response = yield call(fetch, "https://jsonplaceholder.typicode.com/users/1");
const user = yield response.json();
yield put({ type: "FETCH_USER_SUCCESS", payload: user });
} catch (error) {
yield put({ type: "FETCH_USER_FAILURE", error: error.message });
}
}
function* watchFetchUser() {
yield takeEvery("FETCH_USER_REQUEST", fetchUserSaga);
}
export default watchFetchUser;
๐ฅ Redux Saga vs Redux Thunk
Redux Saga์ Thunk๋ ๋ ๋ค ๋น๋๊ธฐ ์์ ์ ์ฒ๋ฆฌํ ์ ์์ง๋ง, ์ ๊ทผ ๋ฐฉ์์ด ๋ค๋ฆ ๋๋ค.
ํน์ง | Redux Thunk | Redux Saga |
๊ธฐ๋ฐ | ํจ์ ๊ธฐ๋ฐ | ์ ๋๋ ์ดํฐ ๊ธฐ๋ฐ |
๋ณต์กํ ์์ ์ฒ๋ฆฌ | ์ด๋ ค์ | ํจ์จ์ |
ํ์ต ๊ณก์ | ๋ฎ์ | ๋์ |
์ ์ค ์ผ์ด์ค | ๊ฐ๋จํ ๋น๋๊ธฐ ๋ก์ง | ๋ณต์กํ ๋น๋๊ธฐ ํ๋ฆ |
๐ ๊ฒฐ๋ก
Redux Saga๋ ๋ณต์กํ ๋น๋๊ธฐ ์์ ์ ๊ด๋ฆฌํ๊ธฐ ์ํ ๊ฐ๋ ฅํ ๋๊ตฌ์ ๋๋ค.
๊ทธ ํ์ ์ ๋๋ ์ดํฐ ํจ์์ ์ดํํธ์ ์กฐํฉ์์ ๋์ค์ฃ . ์ฒ์์๋ ์ฝ๊ฐ ํท๊ฐ๋ฆด ์๋ ์์ง๋ง, ์ต์ํด์ง๋ฉด ์ ๋ง ๊น๋ํ๊ณ ์ ์ฐํ ์ฝ๋๋ฅผ ์์ฑํ ์ ์์ด์.
๐ท์ ์ค์ ๊ฐ๋ฐ์๊ฐ ๋์ด๋ด ์๋น!๐ท