Last active
January 7, 2020 14:56
-
-
Save keslo/783d6647965d5c167c5efdb77cdeecd6 to your computer and use it in GitHub Desktop.
Understanding Redux
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Рассмотрим функцию createStore | |
function createStore(reducer, preloadedState, enhancer) { ... } | |
// При наличии `enchancer` (расширитель) `createStore` вызывается еще раз и возвращает результат выполнения `enchancer` | |
... | |
return enhancer(createStore)(reducer, preloadedState); | |
... | |
// Рассмотрим расширитель на примере `applyMiddleware` | |
function applyMiddleware() { | |
return function (createStore) { | |
return function (reducer, preloadedState, enhancer) { | |
... | |
return Object.assign({}, store, { | |
dispatch: _dispatch | |
}) | |
} | |
} | |
} | |
// При создании экземпляра происходит вызов applyMiddleware (на примере thunk) ... | |
const store = createStore(reducer, applyMiddleware(thunk)); | |
// ... который вернет функцию вида | |
function (createStore) { // (1) | |
return function (reducer, preloadedState) { | |
... | |
} | |
} | |
// Примечание: createStore понимает если вместо preloadedState вторым параметром передается applyMiddleware | |
// Рассмотрим функцию (1) подробнее | |
return function (createStore) { | |
return function (reducer, preloadedState, enhancer) { | |
var store = createStore(reducer, preloadedState); // создаем стандартный store | |
var _dispatch = store.dispatch; // назначаем свойство dispatch в новую переменную _dispatch | |
var chain = []; // новый массив для цепочки middleware-параметров из applyMiddleware | |
var middlewareAPI = { // задаем API для передачи в middleware | |
getState: store.getState, | |
dispatch: function dispatch(action) { | |
return _dispatch(action); | |
} | |
}; | |
chain = middlewares.map(function (middleware) { // передаем в каждую middleware API для работы со store | |
return middleware(middlewareAPI); | |
}); | |
_dispatch = compose.apply(undefined, chain)(store.dispatch); | |
return Object.assign({}, store, { | |
dispatch: _dispatch | |
}); | |
}; | |
}; | |
// Код middleware thunk | |
function createThunkMiddleware(extraArgument) { | |
return ({ dispatch, getState }) => (next) => (action) => { | |
if (typeof action === 'function') { | |
return action(dispatch, getState, extraArgument); | |
} | |
return next(action); | |
} | |
} | |
const thunk = createThunkMiddleware(); | |
thunk.withExtraArgument = createThunkMiddleware; | |
export default thunk; | |
// Данная middleware передается в createStore уже в виде функции | |
({ dispatch, getState }) => next => action => { | |
if (typeof action === 'function') { | |
return action(dispatch, getState, extraArgument); | |
} | |
return next(action); | |
} | |
// thunk получает на вход объект middlewareAPI из (1) | |
// Таким образом вызов в (1) и будет выглядеть так | |
next => action => { | |
if (typeof action === 'function') { return action(dispatch, getState, extraArgument) } | |
return next(action); | |
} | |
// Вызов ... | |
chain = middlewares.map | |
// ... вернет массив chain вида (при одном thunk) | |
[ | |
next => action => { | |
if (typeof action === 'function') { | |
return action(dispatch, getState); | |
} | |
return next(action); | |
] | |
// Далее цепочка вызова middlewares из chain формируется через compose и возвращает функцию | |
// в которую единственным параметром передается store.dispatch | |
_dispatch = compose.apply(undefined, chain)(store.dispatch); // (2) | |
// Вызов compose(f, g, h) идентичен (...args) => f(g(h(...args))) | |
// Таким образом последняя функция h получается реальный dispatch, который при вызове next(action) уже выполнится над store | |
// Вызов middleware начинается слева направо f() -> g() -> h() | |
// Далее возвращаем созданный store с переопределенным методом dispatch | |
return Object.assign({}, store, { | |
dispatch: _dispatch | |
}) | |
// Цепочку вызовов можно прервать просто не вызывая next(action) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment