Skip to content

Instantly share code, notes, and snippets.

@keslo
Last active January 7, 2020 14:56
Show Gist options
  • Save keslo/783d6647965d5c167c5efdb77cdeecd6 to your computer and use it in GitHub Desktop.
Save keslo/783d6647965d5c167c5efdb77cdeecd6 to your computer and use it in GitHub Desktop.
Understanding Redux
// Рассмотрим функцию 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