Анализ усилителя магазина Redux

внешний интерфейс JavaScript React.js Redux

Я полагаю, что все знают концепцию промежуточного программного обеспечения (промежуточного программного обеспечения) Redux.Redux может выполнять такие функции, как отправка асинхронных действий (сетевых запросов) и печать журналов действий через промежуточное программное обеспечение. Условно говоря, многие люди не очень понимают концепцию усилителя магазина Redux.

1. Основные понятия и использование

Redux создает хранилище через API createStore, сигнатура функции createStore выглядит следующим образом:

createStore(reducer, [preloadedState], [enhancer])

Среди них третий необязательный параметр энхансера относится к энхансеру хранилища.

Усилитель магазина, который можно перевести как усилитель магазина, как следует из названия, предназначен для улучшения функции магазина. Усилитель магазина на самом деле является функцией более высокого порядка.Его параметром является функция, которая создает магазин (создатель магазина), а возвращаемое значение — это функция, которая может создать более мощный магазин (создатель расширенного магазина), который похож на функция высокого уровня в React Концепция скалярных компонентов аналогична.

Функция Enhancer Store Store обычно выглядит следующим образом:

function enhancerCreator() {
  return createStore => (...args) => {
    // do something based old store
    // return a new enhanced store
  }
}

Заметьте, чтоEnhancerCreator — это функция, используемая для создания усилителя хранилища, то есть результатом выполнения функцииEnhancerCreator является расширитель хранилища. (...args) Параметр представляет параметры, необходимые для создания хранилища, то есть параметры, полученные createStore, которые на самом деле являются (reducer, [preloadedState], [enhancer]).

Теперь давайте создадим усилитель магазина, который выводит информацию об отправленном действии и изменениях состояния:

// autoLogger.js
// store enhancer
export default function autoLogger() {
  return createStore => (reducer, initialState, enhancer) => {
    const store = createStore(reducer, initialState, enhancer)
    function dispatch(action) {
      console.log(`dispatch an action: ${JSON.stringify(action)}`);
      const res = store.dispatch(action);
      const newState = store.getState();
      console.log(`current state: ${JSON.stringify(newState)}`);
      return res;
    }
    return {...store, dispatch}
  }
}

autoLogger() изменяет поведение по умолчанию для диспетчеризации хранилища, которое будет выводить информацию журнала до и после отправки каждого действия. Затем при создании хранилища используйте расширитель хранилища autoLogger():

// configureStore.js
import { createStore, applyMiddleware } from 'redux';
import rootReducer from 'path/to/reducers';
import autLogger from 'path/to/autoLogger';

const store = createStore(
  reducer,
  autoLogger()
);

2. Связь с промежуточным ПО (middleware)

Если вы понимаете redux-logger, промежуточное программное обеспечение redux, считаете ли вы, что функция autoLogger() похожа на него? Могут ли усилитель хранилища и ПО промежуточного слоя выполнять одну и ту же функцию? Оно делает. На самом деле, функция реализации промежуточного программного обеспечения, а именно applyMiddleware, является усилителем хранилища.Исходный код applyMiddleware выглядит следующим образом:

export default function applyMiddleware(...middlewares) {
  return createStore => (...args) => {
    // 省略
    return {
      ...store,
      dispatch
    }
  }
}

Структура applyMiddleware точно такая же, как у упомянутого выше усилителя хранилища.Результатом выполнения applyMiddleware(...middlewares) является усилитель хранилища. Следовательно, функции, которые могут быть реализованы промежуточным программным обеспечением, также могут быть реализованы усилителем хранилища. Из окончательной возвращаемой структуры {...store, dispatch} для applyMiddleware(...middlewares) можно сделать вывод, что усилитель хранилища для applyMiddleware(...middlewares) в основном используется для изменения метода отправки хранилища, который действительно является промежуточным программным обеспечением Роль: Улучшить диспетчерскую функцию магазина. Промежуточное ПО на самом деле представляет собой уровень абстракции над усилителем хранилища для applyMiddleware(...middlewares), applyMiddleware(...middlewares) передается каждому параметру промежуточного ПО {getState, dispatch}, а промежуточное ПО усиливает метод отправки.

При одновременном использовании applyMiddleware(...middlewares) и других расширителей хранилища вы часто можете использовать функцию компоновки, предоставляемую redux, чтобы объединить эти усилители хранилища в один:

// configureStore.js
import { createStore, applyMiddleware, compose } from 'redux';
import rootReducer from 'path/to/reducers';
import autLogger from 'path/to/autoLogger';

const enhancer = compose(
  applyMiddleware(...middlewares),
  autLogger()
);

const store = createStore(
  reducer,
  enhancer
);

После объединения компоновки все энхансеры хранилища образуют луковичную модель. Первый энхансер в композиции находится на самом внешнем уровне луковичной модели, а последний энхансер — на самом внутреннем слое луковичной модели. Всякий раз, когда отправляется действие, оно будет пройти через лук.Обработка каждого слоя энхансера снаружи внутрь модели показана на следующем рисунке. Поскольку мы обычно обрабатываем асинхронные действия через ПО промежуточного слоя, чтобы гарантировать, что другие энхансеры получают обычные действия, нам нужно передать applyMiddleware(...middlewares) в качестве первого компоновщика хранилища, чтобы все действия проходили через applyMiddleware(. .. промежуточное ПО).

图 1

applyMiddleware(...middlewares) ограничивает промежуточное ПО только улучшением функции отправки хранилища, но это только его собственное ограничение спецификации. Для других усилителей хранилища вы можете улучшить функцию любого метода, содержащегося в хранилище, например отправки, подписки , getState, replaceReducer и т. д. В конце концов, магазин — это всего лишь простой объект JavaScript с некоторыми функциями, которые можно легко скопировать и добавить новые функции.

Давайте посмотрим на другой пример,redux-localstorage, этот усилитель хранилища используется для автоматического сохранения состояния в хранилище в localStorage. Его основной код выглядит следующим образом:

// store enhancer
export default function persistState(paths, config) {
  // 一些功能选项配置

  return next => (reducer, initialState, enhancer) => {
    let persistedState
    let finalInitialState

    try {
      persistedState = deserialize(localStorage.getItem(key))
      finalInitialState = merge(initialState, persistedState)
    } catch (e) {
      console.warn('Failed to retrieve initialize state from localStorage:', e)
    }

    const store = next(reducer, finalInitialState, enhancer)
    const slicerFn = slicer(paths)
    
    // 主要代码
    store.subscribe(function () {
      const state = store.getState()
      const subset = slicerFn(state)

      try {
        localStorage.setItem(key, serialize(subset))
      } catch (e) {
        console.warn('Unable to persist state to localStorage:', e)
      }
    })

    return store
  }
}

То, что делает этот энхансер, на самом деле очень просто.После создания хранилища он сразу подписывается на изменения хранилища.При изменении состояния в хранилище состояние сохраняется в localStorage.

3. Разрушительный усилитель

Поскольку Enhancer Store мы свободны для копирования, хранятся в методе изменения, поэтому в информировании пользовательских магазинов, поскольку может возникнуть повреждение нормального рабочего потока Redux, заставляя все приложение не работает. Вот пример разрушительного усилителя:

export default function breakingEnhancer() {
  return createStore => (reducer, initialState, enhancer) => {
    const store = createStore(reducer, initialState, enhancer)
    function dispatch(action) {
      console.log(`dispatch an action: ${JSON.stringify(action)}`);
      console.log(`current state: ${JSON.stringify(newState)}`);
      return res;
    }
    return {...store, dispatch}
  }
}

В этом примере воссоздается метод диспетчеризации, но в новом методе диспетчеризации старый метод диспетчеризации не вызывается для отправки действия, поэтому действие не может быть отправлено нормально, и все приложение, естественно, не может работать. Поэтому при настройке усилителя магазина вы должны быть осторожны, чтобы не разрушить исходный рабочий процесс Redux.


Добро пожаловать, чтобы обратить внимание на мою официальную учетную запись: большой фронт-энд ветеранских кадров и получить 21 избранную книгу большого фронт-энда!