๐ https://github.com/happypoulp/redux-tutorial/wiki
Tutorial 09 - middleware
์ฐ๋ฆฌ๋ ์ด์ ์ ์๋ก์ด ๊ฐ๋ โ๋ฏธ๋ค์จ์ดโ๋ฅผ ๊ณผ์ ๋ก ๋จ๊ฒจ๋จ์๋ค. ๋ฏธ๋ค์จ์ด๊ฐ ์ด๋ป๊ฒ ๋น๋๊ธฐ ์ก์ ์ ๋ค๋ฃฐ ์ ์๊ฒ ๋์์ค ์ ์๋๊ฑธ๊น. ๊ทธ๋์ ๋์ฒด ๋ฏธ๋ค์จ์๊ฐ ๋ฌด์์ผ๊น?
์ผ๋ฐ์ ์ผ๋ก ๋ฏธ๋ค์จ์ด๋ ์ ํ๋ฆฌ์ผ์ด์ ์ A์ B ์ฌ์ด ์ผ๋ถ์์ A๊ฐ B์๊ฒ ์ ๋ฌํ๊ธฐ ์ ์ ๋ณํ์ํค๊ฒ ํ๊ธฐ์ํ ๊ฒ์ด๋ค. ๊ทธ๋์ A โโ> B ๋์ , A โ> middleware 1 โ> middleware 2 โ> middleware 3 โ> โฆ โ> B ์ด๋ฐ ์์ผ๋กโฆ
๋ฆฌ๋์ค์์ ๋ฏธ๋ค์จ์ด๋ ์ฐ๋ฆฌ๋ฅผ ์ด๋ป๊ฒ ๋์์ค๊น? ์ ์ฐ๋ฆฌ๊ฐ ๋ง๋ค์๋ ๋น๋๊ธฐ ์ก์ creator๋ ๊ทธ๋ฅ ๋ฆฌ๋์ค๋ก๋ ๋ค๋ฃฐ ์ ์์์ง๋ง ๋ฏธ๋ค์จ์ด๊ฐ ์ก์ creator์ reducer ์ฌ์ด์ ์๋ค๋ฉด, ์ด ํจ์๋ฅผ ๋ฆฌ๋์ค์ ๋ง๋ ์ด๋ค๊ฒ์ผ๋ก ๋ฐ๊ฟ ์ ์๋ค:
action โ> dispatcher โ> middleware 1 โ> middleware 2 โ> reducers
๊ฐ ์ก์ ๋ง๋ค (ํน์ ์ฐ๋ฆฌ๊ฐ ๋ง๋ค์๋ ๋น๋๊ธฐ ์ก์ creator ๊ฐ์ ๊ฒฝ์ฐ์ ํจ์์ฒ๋ผ ์ด๋ค๊ฒ์ด๋ ) ๋ฏธ๋ค์จ์ด๋ฅผ ํธ์ถํ ์ ์๊ณ dispatch ๋๋ค. ์ด๊ฒ์ด ์ฐ๋ฆฌ๊ฐ ์ํ ๋(์๋๋ฉด ์๋ฌด๊ฒ๋ ํ์ง ์๋๋ก ํ๊ฑฐ๋ - ์ด๊ฒ์ ๋๋๋ก ํ์ํ ํ๋์) ์ก์ creator๊ฐ ์ค์ ์ก์ ์ dispatch ํ ์ ์๊ฒ ๋์์ค๋ค.
๋ฆฌ๋์ค์์ ๋ฏธ๋ค์จ์ด๋ ๋งค์ฐ ๊ตฌ์ฒด์ ์ธ ํน์ง๊ณผ ์๊ฒฉํ ๊ตฌ์กฐ๋ฅผ ๋ฐ๋ผ์ผํ๋ ํจ์์ด๋ค.
var anyMiddleware = function ({ dispatch, getState }) {
return function(next) {
return function (action) {
// ๊ตฌ์ฒด์ ์ธ ์ฝ๋๋ ์ด๊ณณ์
}
}
}
์์์ ๋ณด์๋ค์ํผ, ๋ฏธ๋ค์จ์ด๋ 3๊ฐ์ ์ค์ฒฉ๋ ํจ์๋ก ๊ตฌ์ฑ๋์ด์๋ค(์ฐ์์ ์ผ๋ก ํธ์ถ๋ ๊ฒ์):
- ์ฒซ๋ฒ์งธ ํจ์๋
dispatch
์getState
ํจ์๋ฅผ(๋ง์ฝ ๋ฏธ๋ค์จ์ด๋ action creator ๊ฐ ์ํ์์ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ด์ผ ํ๋ค๋ฉด) ๋จ์ 2๊ฐ์ ํจ์์ ์ ๊ณตํ๋ค. - ๋๋ฒ์งธ๋
next
ํจ์๋ฅผ ์ ๊ณตํ๋๋ฐ ๋ณํ๋ ์ธํ์ ๋ค์ ๋ฏธ๋ค์จ์ด ํน์ ๋ฆฌ๋์ค์ ๋ช ํํ๊ฒ ์ ๋ฌํด์ค ์ ์๊ฒ ํด์ค๋ค(๋ฆฌ๋์ค๊ฐ ๋ชจ๋ ๋ฆฌ๋์๋ค์ ํธ์ถํ ์ ์๊ฒํ๊ธฐ ์ํจ). - ์ธ๋ฒ์งธ๋ ์ด์ ๋ฏธ๋ค์จ์ด์์ ํน์ dispatch์์ ๋ฐ์ ์ก์ ์ ์ ๊ณตํ๊ณ ๋ค์ ๋ฏธ๋ค์จ์ด๋ฅผ ์คํ์ํฌ ์ ์๋ค(์ก์ ์ด ๊ณ์ํด์ ํ๋ฌ๊ฐ๊ธฐ ์ํจ). ๋๋ ๋ค๋ฅธ ์ ์ ํ ๋ฐฉ๋ฒ์ผ๋ก ์ก์ ์ ์งํ์ํจ๋ค.
๋ง์ฝ ํจ์ํ ํ๋ก๊ทธ๋๋ฐ์ ๋ํด ํ์ต์ ํด๋ณธ์ฌ๋์ด๋ผ๋ฉด ์์์ ํจ์ํ ํจํด์ ์ ์ฉํ ์ ์๋ ๋ถ๋ถ์ ๋ฐ๊ฒฌํ์ ๊ฒ์ด๋ค: ์ปค๋ง์ ์ด์ฉํ๋ฉด ๊ฐ๋จํ๊ฒ ์ ํจ์๋ฅผ ์ด๋ฐ์์ผ๋ก ํ ์ ์๋ค. ๋ชฐ๋ผ๋ ๊ด์ฐฎ๋ค. ์ด ๋ถ๋ถ์ ๊ฑด๋๋ฐ์ด๋ ๋ฆฌ๋์ค๋ฅผ ์ดํดํ๋๋ฐ ์๋ฌด๋ฐ ์ง์ฅ์ด ์๋ค
// ํจ์ํ ํ๋ก๊ทธ๋๋ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ๊ฐ์ ธ์จ `curry`(lodash, ramda ๋ฑ๋ฑ)
var thunkMiddleware = curry(
({dispatch, getState}, next, action) => (
// ๊ตฌ์ฒด์ ์ธ ์ฝ๋๋ ์ด๊ณณ์
)
);
๋น๋๊ธฐ ์ก์ creator ๋ฅผ ๋ง๋ค๊ธฐ์ํ ๋ฏธ๋ค์จ์ด๋ฅผ thunk ๋ฏธ๋ค์จ์ด๋ผ๊ณ ๋ถ๋ฅด๊ณ ์ฝ๋๋ ์ฌ๊ธฐ์์ ๊ฐ์ ธ์๋๋ฐ ์ด๋ฐ์์ด๋ค(๊ฐ๋ ์ฑ์ ๋์ด๊ธฐ ์ํด es5๋ฌธ๋ฒ์ผ๋ก ํจ์ ๋ณธ๋ฌธ์ ์์ ํจ)
var thunkMiddleware = function ({ dispatch, getState }) {
// console.log('Enter thunkMiddleware');
return function(next) {
// console.log('Function "next" provided:', next);
return function (action) {
// console.log('Handling action:', action);
return typeof action === 'function' ?
action(dispatch, getState) :
next(action)
}
}
}
ํ๋ ๋๋ ์ฌ๋ฌ๊ฐ์ ๋ฏธ๋ค์จ์ด๋ฅผ ์ฐ๋ ค๋ฉด ๋ฆฌ๋์ค์ helper ํจ์๋ฅผ ์ฌ์ฉํด์ผํ๋ค: applyMiddleware.
โapplyMiddlewareโ๋ ๋ฏธ๋ค์จ์ด๋ค์ ํ๋ผ๋ฏธํฐ๋ก ๊ฐ๊ณ ์๊ณ createStore์ ํจ๊ป ํธ์ถ๋๋ ํจ์๋ฅผ ๋ฆฌํดํ๋ค. ๋ง์ง๋ง ํจ์๊ฐ ์คํ๋๋ฉด, โstore์ dispatch์ ๋ฏธ๋ค์จ์ด๊ฐ ์ถ๊ฐ๋ ๊ณ ์ฐจ storeโ๊ฐ ๋ง๋ค์ด์ง๋ค.(์ฐธ๊ณ https://github.com/reactjs/redux/blob/master/src/applyMiddleware.js)
์ฌ๊ธฐ ๋ฆฌ๋์ค store์ ๋ฏธ๋ค์จ์ด๋ฅผ ํตํฉํ๋ ๋ฐฉ๋ฒ์ด ์๋ค.
import { createStore, combineReducers, applyMiddleware } from 'redux'
const finalCreateStore = applyMiddleware(thunkMiddleware)(createStore)
// ๋ฏธ๋ค์จ์ด๋ฅผ ์ฌ๋ฌ๊ฐ ์ธ๋: applyMiddleware(middleware1, middleware2, ...)(createStore)
var reducer = combineReducers({
speaker: function (state = {}, action) {
console.log('speaker ๊ฐ ์ ๋ฌ๋ฐ์ ์ํ', state, '์ ์ก์
', action)
switch (action.type) {
case 'SAY':
return {
...state,
message: action.message
}
default:
return state
}
}
})
const store_0 = finalCreateStore(reducer)
// Output:
// speaker ๊ฐ ์ ๋ฌ๋ฐ์ ์ํ {} ์ ์ก์
{ type: '@@redux/INIT' }
// speaker ๊ฐ ์ ๋ฌ๋ฐ์ ์ํ {} ์ ์ก์
{ type: 'type: '@@redux/PROBE_UNKNOWN_ACTION_s.b.4.z.a.x.a.j.o.r' }
// speaker ๊ฐ ์ ๋ฌ๋ฐ์ ์ํ {} ์ ์ก์
{ type: 'type: @@redux/INIT' }
์ด์ middleware๋ก ๋ค์ ๋น๋๊ธฐ์ก์ ์ dispatch ํด๋ณด์:
var asyncSayActionCreator_1 = function (message) {
return function (dispatch) {
setTimeout(function () {
console.log(new Date(), '์ก์
Dispatch')
dispatch({
type: 'SAY',
message
})
}, 2000)
}
}
console.log("\n", new Date(), '๋น๋๊ธฐ action creator ํธ์ถ:', "\n")
store_0.dispatch(asyncSayActionCreator_1('Hi'))
// Output:
// Mon Aug 03 2015 00:01:20 GMT+0200 (CEST) ๋น๋๊ธฐ action creator ํธ์ถ:
// Mon Aug 03 2015 00:01:22 GMT+0200 (CEST) '์ก์
Dispatch'
// speaker ๊ฐ ์ ๋ฌ๋ฐ์ ์ํ {} ์ ์ก์
{ type: 'SAY', message: 'Hi' }
// ๋น๋๊ธฐ action creator ํธ์ถ๋ก ์ ํํ 2์ด ๋ค์ dispatch ๋จ!
// dispatch ๋ ์ก์
์ ๋ก๊ทธ๋ก ์ฐ์ด๋ณด๋ ๋ฐฉ๋ฒ:
function logMiddleware ({ dispatch, getState }) {
return function(next) {
return function (action) {
console.log('logMiddleware๊ฐ ๋ฐ์ ์ก์
:', action)
return next(action)
}
}
}
dispatch๋ ์ก์ ๋ค์ ๊ฑด๋๋ฐ๋ ๋ฐฉ๋ฒ(์ด๋๋ก๋ ์ฐ๊ธฐ๋ณด๋ค๋ ๋ก์ง์ ์ข ๋ ์ถ๊ฐํด์ ์ผ๋ถ ์ก์ ๋ค๋ง ์ ํํด์ ๋ค์ ๋ฏธ๋ค์จ์ด๋ ๋ฆฌ๋์ค์ ์ ๋ฌ๋์ง ์๊ฒ ํ ์ ์๋ค):
function discardMiddleware ({ dispatch, getState }) {
return function(next) {
return function (action) {
console.log('discardMiddleware๊ฐ ๋ฐ์ ์ก์
:', action)
}
}
}
finalCreateStore ์์ ์์ logMiddleware ๋ discardMiddleware ๋ฅผ ํธ์ถํด๋ณด๋ฉดโฆ ์๋ฅผ ๋ค์ด, ์ด๋ ๊ฒ ์ฐ๊ณ :
const finalCreateStore = applyMiddleware(discardMiddleware, thunkMiddleware)(createStore)
์ก์ ์ด thunkMiddleware ์ ๋ฆฌ๋์์ ์ ๋ฌ๋์ง ์์์ผํ๋ค.
http://redux.js.org/docs/introduction/Ecosystem.html#middleware ์ฌ๊ธฐ์์ ๋ค๋ฅธ ๋ฏธ๋ค์จ์ด ์์ ๋ค์ ๋ ํ์ธํ ์ ์๋ค.
์ง๊ธ๊น์ง ๋ฐฐ์ด ๊ฒ์ ์ข ํฉํด๋ณด๋ฉด:
- ์ก์ ๊ณผ ์ก์ creator ์ฐ๋ ๋ฐฉ๋ฒ
- ์ก์ ์ dispatch ํ๋ ๋ฐฉ๋ฒ
- ๋ฏธ๋ค์จ์ด๋ก ๋น๋๊ธฐ์ก์ ๊ฐ์ ์ปค์คํ ํ ์ก์ ์ ๋ค๋ฃจ๋ ๋ฐฉ๋ฒ
Flux ์ ํ๋ฆฌ์ผ์ด์ ์ ํ๋ก์ฐ์์ ๋จ์ ๋ถ๋ถ์ ์ํ๊ฐ ๊ฐฑ์ ๋จ์ ์๋ฆฌ๋ ๋ถ๋ถ์ธ๋ฐ ์ด๋ป๊ฒ ๋ฆฌ๋์ค store ๊ฐฑ์ ์ ๊ตฌ๋ ํ ์ ์๋๊ฑธ๊น?
๋ค์: 10_state-subscriber.md