Используя 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