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
λ₯Ό μ€ννλ€.μ°Έκ³