
react μ€ν°λμμ 리μ‘νΈλ₯Ό λ€λ£¨λ κΈ°μ μ΄λΌλ μ± μ μ μ νκ³ μ΄ μ± μ μ½κ³ λ°°μ΄ κ²μ λ°νμΌλ‘ μμ±λμλ€.
π‘ μ‘μ κ³Ό 리λμ μ¬μ΄μ μ€κ°μ
dispatchλμμ λ 리λμμμ μ΄λ₯Ό μ²λ¦¬νκΈ°μ μμ μ§μ λ μμ
λ€μ μ€ννλ€.const loggerMiddleware = store => next => action => {
};
μ°Έκ³ : ν΄λ‘μ (컀λ§ν¨μ)
store: 리λμ€ μ€ν μ΄ μΈμ€ν΄μ€action: λμ€ν¨μΉλ μ‘μ
next: ν¨μ ννλ‘ dispatchμ λΉμ·ν κΈ°λ₯μ νλ€.next(action)μ νΈμΆνλ©΄ μ‘μ
μ λ€μ λ―Έλ€μ¨μ΄μκ² μ λ¬νκ³ , μλ€λ©΄ 리λμμκ² μ λ¬νλ€.store.dispatchλ₯Ό νΈμΆνλ©΄ 첫 λ²μ§Έ λ―Έλ€μ¨μ΄λΆν° λ€μ μ²λ¦¬νλ€.nextλ₯Ό μ¬μ©νμ§ μμΌλ©΄ μ‘μ
μ 리λμμκ² μ λ¬λμ§ μλλ€. μ¦, μ‘μ
μ΄ λ¬΄μλλ€.// src/index.js
import { createStore, applyMiddleware } from "redux";
import { createLogger} from "redux-logger";
import rootReducer from "./modules";
const logger = createLogger();
const store = createStore(rootReducer, applyMiddleward(logger));
Thunk: νΉμ μμ
μ λμ€μ ν μ μλλ‘ λ―Έλ£¨κΈ° μν΄ ν¨μ ννλ‘ κ°μΌ κ²μ μλ―Ένλ€.const addOne = x => x + 1;
const addOneThunk = x => () => addOne(x);
const fn = addOneThunk(1);
setTimeout(() =>{
const value = fn();
console.log(value);
}, 1000);
redux-thunkλΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μ©νλ©΄ ν¨μ ννμ μ‘μ
μ λμ€ν¨μΉν μ μλ€. κ·Έλ¬λ©΄ 리λμ€ λ―Έλ€μ¨μ΄κ° κ·Έ ν¨μλ₯Ό μ λ¬λ°μ storeμ dispatchμ getStateλ₯Ό μΈμλ‘ λ£μ΄ ν¨μλ₯Ό νΈμΆνλ€.const sampleThunk = () => (dispatch, getState) => {
// νμ¬ μν μ‘°ν
// μλ‘μ΄ μ‘μ
λμ€ν¨μΉ
};
// src/index.js
import { createStore, applyMiddleware } from "redux";
import ReduxThunk from "redux-thunk";
import rootReducer from "./modules";
const store = createStore(rootReducer, applyMiddleward(ReduxThunk));
κΈ°λ³Έ κ°λ μ€μ¬μΌλ‘ μμ±λμλ€.
redux-sagaλ μ ν리μΌμ΄μ
μ side effectλ€μ μ½κ² κ΄λ¦¬νκ³ ν¨κ³Όμ μΌλ‘ μ€ννκ³ κ°λ¨ν ν
μ€νΈμ μ¬μ΄ μλ¬ μ²λ¦¬λ₯Ό λͺ©μ μΌλ‘ νλ€.side effectλ₯Ό λ³λμ μ€λ λλ‘ λΆλ¦¬ν΄μ κ΄λ¦¬ν μ μλ€.side effect: λ°μ΄ν° μμ² λ±μ λΉλκΈ° μμ
, λΈλΌμ°μ μΊμ λ±κ³Ό κ°μ΄ μμνμ§ μμ κ²λ€redux-sagaλ₯Ό μ΄μ©νμ¬ μ¬μ΄νΈ μ΄ννΈλ₯Ό κ΄λ¦¬ν μ μλ€.
redux-sagaλΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μ©νλ κ²½μ°
- κΈ°μ‘΄ μμ²μ μ·¨μ μ²λ¦¬ν΄μΌ ν λ (λΆνμν μ€λ³΅ μμ² λ°©μ§)
- νΉμ μ‘μ μ΄ λ°μνμ λ λ€λ₯Έ μ‘μ μ λ°μμν€κ±°λ API μμ² λ± λ¦¬λμ€μ κ΄κ³μλ μ½λλ₯Ό μ€νν λ
- μΉμμΌμ μ¬μ©ν λ
- API μμ² μ€ν¨ μ μ¬μμ²ν΄μΌ ν λ
import { put, takeEvery } from "redux-saga/effect";
function* helloSaga(){
console.log("hello saga");
}
// worker Saga: will perform the async increment task
function* incrementAsync(){
yield delay(1000);
yield put({ type: "INCREMENT" });
}
// watcher Saga: spawn a new incrementAsync task on each INCREMENT_ASYNC action
function* watchIncrementAsync(){
yield takeEvery("INCREMENT_ASYNC", incrementAsync);
}
// root Saga
export default function* rootSaga() {
yield all([
helloSaga(),
watchIncrementAsync()
]);
}
Sagaλ κ°μ²΄λ₯Ό yieldνλ μ λλ μ΄ν° ν¨μμ΄λ€.yielded object)λ λ―Έλ€μ¨μ΄μκ² μ λ¬νλ μΌμ’
μ λͺ
λ Ήμ΄λ€.Sagaκ° λ°νν κ°μ²΄ (yielded object)λ₯Ό λ°κ³ λͺ
λ Ήμ ν΄μνμ¬ νΉμ μμ
μ μννλ€. κ·Έ λμ Sagaλ μ€νμ΄ μ€μ§λ μνμ΄λ€.Sagaλ₯Ό λ³λ ¬μ μΌλ‘ μ€νν μ μλλ‘ root Sagaλ₯Ό λ§λ λ€.const sagaMiddleware = createSagaMiddleware();
const store = createStore(reducer, applyMiddleware(sagaMiddleware);
sagaMiddleware.run(rootSaga);
redux-sagaλ μ λλ μ΄ν° ν¨μ λ¬Έλ²μ κΈ°λ°μΌλ‘ side effectμ κ΄λ¦¬νλ€.function*)λ₯Ό νΈμΆνλ©΄ μ λλ μ΄ν°κ° λ°νλλ€.next()λ©μλλ₯Ό κ°λλ° μ΄ λ©μλλ₯Ό νΈμΆνλ©΄ μ λλ μ΄ν° ν¨μλ yieldλ¬Έμ λ§λκΈ° μ κΉμ§ μ€νλλ€.next()λ©μλλ₯Ό νΈμΆνλ©΄ μ€νμ΄ μ€μ§λ μμ λΆν° λ€μ μ λλ μ΄ν° ν¨μκ° μ€νλλ€.β μ λλ μ΄ν° ν¨μλ
Callee, μ΄λ₯Ό νΈμΆνλ ν¨μλCallerμ΄λ€.
β Caller Calleeκ° λ°νν μ λλ μ΄ν°λ₯Ό κ°μ§κ³ λ‘μ§μ μννλ€.
β Callerλ Calleeμyieldμ§μ μμ λ€μ μ§ν μ¬λΆ/μμ μ μ μ΄νλ€.
β Callerλ Calleeλ₯Ό νΈμΆνλ μ± μλΏ μλλΌ Callee λ΄λΆ λ‘μ§ μνμ λν μ μ΄κΆμ κ°λλ€.
redux-saga μ
μ₯μμ 보면 λ―Έλ€μ¨μ΄κ° Callerμ΄κ³ , μ λλ μ΄ν° ν¨μμΈ Sagaκ° Calleeλ€.Sagaλ₯Ό λμμμ΄ λμμν¨λ€.Sagaκ° λμνκΈ° μμνλ©΄ μ λλ μ΄ν° ν¨μμ΄κΈ° λλ¬Έμ yieldλ¬Έμ λ§λλ©΄ μ€νμ΄ μ€μ§λκ³ κ°μ²΄λ₯Ό yieldνλ€.π‘ λ―Έλ€μ¨μ΄μ μν΄ μνλ λͺ λ Ήμ λ΄κ³ μλ μμν μλ°μ€ν¬λ¦½νΈ κ°μ²΄
// μμ λ΄€λ μ½λ
function* incrementAsync(){
yield delay(1000);
yield put({ type: "INCREMENT" });
}
delay(1000)λ₯Ό μ€ννμ¬ Promiseκ°μ²΄λ₯Ό λ°ννλ€. μ¦, ν¨μ λ΄λΆμ λΉλμ μΈ λ‘μ§μ΄ μ‘΄μ¬νλ€.// μμ λ μ½λ
function* incrementAsync(){
yield call(delay, 1000); // {CALL : {fn: delay, args: [1000]}}
yield put({ type: "INCREMENT" }); // {PUT: {type: "INCREMENT"}}
}
callμ΄λ putμ Effect Creators(μ΄ννΈ μμ±μ)λΌκ³ νκ³ , λͺ
λ Ήμ λ΄κ³ μλ μμν κ°μ²΄ (Effect)λ₯Ό yieldνλ€.Sagaμκ² μ λ¬νλ€.Sagaλ Effectλ§μ yieldν΄μΌ νλ κ²μ μλλ€. Promise κ°μ²΄λ yieldν μ μμ§λ§ λΉλκΈ° λ‘μ§μ Saga λ΄λΆμμ μ§μ μ²λ¦¬νλ©΄ ν
μ€νΈκ° μ΄λ €μμ§λ λ± μ¬λ¬ μ΄λ €μμ΄ λ°μνλ€.Effectλ§μ yieldνλ Sagaλ₯Ό λ§λ€μ΄μΌ νλ€.
Saga λ΄λΆμμ errorλ₯Ό μ²λ¦¬νκΈ° μν΄ try/catchλ¬Έμ μ¬μ©νλ€.Sagaκ° μ€νλλ κ²takeEvery(action, sagaFn)
actionμ΄ λ°μν λλ§λ€ Sagaλ₯Ό μ€ννλ€. Taskλ₯Ό λμμ μμν μ μλ€.takeLast(action, sagaFn)
actionμ λν΄μλ§ Sagaλ₯Ό μ€ννλ€.Taskλ₯Ό μ·¨μνκ³ μλ‘μ΄ Taskλ₯Ό μ€ννλ€.μ°Έκ³