Используя Vue и Vuex, я прошел через разные сценарии со сложными аспектами, и в этой статье я хотел бы поделиться своими мыслями о создании модулей с помощью Vuex. хранить.

Во время разработки у меня была возможность разрабатывать приложения с помощью React и Redux, Flux и т. Д., Так что поток, представленный Vuex, довольно приятный. знакомо мне, и у меня не было трудностей с его усвоением или с попытками применить к нему свой образ мышления. На самом деле, в чем разница, так это то, как Vuex предлагает начать: единое хранилище с глобальными действиями, мутациями, геттерами, модулями с разделением по состоянию и именам (при необходимости). Вместо того, чтобы рассматривать несколько хранилищ, я предпочел бы сосредоточиться на модулях с разделением имен с динамической инициализацией, поскольку глобальные и общие модули довольно сложны при создании большой базы кода.

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

Почему? Потому что изоляция концепции кажется более безопасной, чистой и дает лучшее понимание потока и того, где манипулируют данными.

Следуя документации Vuex, довольно легко создавать модули с разделением имен, использовать открытые помощники для соединения модулей с созданными компонентами и динамической их регистрации.

Прежде всего, давайте приступим к определению модулей с разделением имен:

// store/modules/cart/index.js
import * as actions from './actions';
import * as getters from './getters';
import * as mutations from './mutations';
const state = { 
  items: 0
};
const namespaced = true;
export default {
  namespaced,
  state,
  actions,
  getters,
  mutations
};

// store/index.js
import cart from './modules/cart/index';
export default new Vuex.Store({
  ...
  modules: {
    cart
  },
  ...
})

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

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

Ответ: мы можем полагаться на динамически создаваемые модули и соединять их с теми компонентами, которые нам нужны.

Как: Vuex предлагает способ регистрации модулей во время выполнения с помощью функции registerModule:

// register a module `myModule` 
store.registerModule('myModule', {   // ... })  
// register a nested module `nested/myModule` store.registerModule(['nested', 'myModule'], {   // ... })
// to unregister a module `myModule`
store.unregisterModule('myModule')

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

Например, у нас может быть приложение с несколькими страницами, где каждой странице назначен компонент (несколько похожих компонентов), который необходимо связать с тем же модулем, который мы хотим использовать повторно, но с учетом изоляции данных (поскольку разные компоненты может иметь другое поведение). Поскольку компоненты различаются, но модуль, который мы хотим использовать, тот же, мы можем продолжить определение общего модуля и зарегистрировать новый экземпляр для каждого компонента, который у нас есть (избегая создания n модулей для m компонентов).

В приведенном ниже примере компонент будет отображать заголовок и случайно сгенерированную переменную, связанную с состоянием модуля.

Начнем с общего модуля:

import actions from './actions';
import getters from './getters';
import mutations from './mutations';

const namespaced = true;

export default {
  namespaced,
  state () {
    return {
      items: 0
    }
  },
  actions,
  getters,
  mutations
};

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

  • Типы:
export default {
  SUCCESS: 'SUCCESS'
};
  • Действия:
import types from './types';
const randomInt = (min, max) => ...;
const generate = ({ commit, state }, options = {}) => {
  const { min = 0, max = 100 } = options;
  // async mock
  setTimeout(() => {
    commit(types.SUCCESS, {
      items: randomInt(min, max)
    });
  }, 5000);
};

export default {
  generate
};
  • Мутации:
import types from './types';

const success = (state, obj) => {
  state.items = obj.items;
};

export default {
  [types.SUCCESS]: success
};
  • Геттеры:
const getItems = (state) => {
  return state.items;
};

export default {
  getItems
};

Конечно, экземпляр Vuex будет объявлен с пустыми модулями при создании нового.

Затронутый компонент может выглядеть следующим образом:

<template>
  <div>
    Home
    <div>
      Items: {{items}}
    </div>
  </div>
</template>

<script>
  import { mapState, mapActions } from 'vuex';
  import commonModule from '../store/modules/common/index';
  const name = 'home';
  export default {
    created: function () {
      const store = this.$store;
     // register a new module only if doesn't exist
     if (!(store && store.state && store.state[name])) {
        store.registerModule(name, commonModule);
      } else {
        // re-use the already existing module
        console.log(`reusing module: ${name}`);
      }
    },
    computed: {
    // map the state from the given namespace
    ...mapState(name, {
        items: state => state.items
      })
    },
    methods:{  
      // map actions from the given namespace
      ...mapActions(name, ['generate'])
    },
    mounted: function () {
      this.generate();
    },
  };
</script>

В качестве примера мы используем ловушку created для регистрации нового модуля и отображения состояния и действий внутри компонента. Конечно, создание экземпляра может произойти где-то еще (средства навигации, крючки маршрутизатора и т. Д.), Но я хотел бы продемонстрировать это как можно проще.

Кроме того, нам необходимо определить, существует ли уже модуль, и если он существует, имеет смысл использовать его повторно.

Если вы внимательно посмотрите на код, мы регистрируем модуль только в том случае, если он не существует, а когда он есть, мы просто повторно используем экземпляр, который у нас есть, с сохраненным состоянием (на всякий случай).

Главное в этом подходе - простота наличия большого количества компонентов, полагающихся на один и тот же модуль (повторно созданных для каждого компонента), и это обеспечивает согласованность данных. Кроме того, что мне нравится, это, по сути, способность разрешать действия / мутации сами по себе и их атомарность, не беспокоясь о том, что связанный компонент монтируется или размонтируется.

Я также создал пример более высокой сложности:

Если вы хотите взглянуть на исходный код, не стесняйтесь проверить следующее репо: https://github.com/cdbkr/vue-dynamic-modules