Как я могу использовать вложенные модули vuex?

#vue.js #vuex #vuex-modules

#vue.js #vuex #vuex-модули

Вопрос:

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

Это моя структура хранилища

 store
 |- modules
   |- core
     |- country.js
     |- region.js
     |- ...
   |- roullout
     |- site.js
 |- index.js
  

Здесь регистрируется модуль index.js

 import Vuex from 'vuex'
// Core modules
import coreCountry from "@/store/modules/core/country";
import coreRegion from "@/store/modules/core/region";
// Rollout modules
import rolloutSite from "@/store/modules/rollout/site";

export default new Vuex.Store({
  modules: {
    // Core modules
    core: {
      country: coreCountry,
      region: coreRegion,
    },
    // Rollout modules
    rollout: {
      site: rolloutSite
    }
  }
})
  

Теперь в каком-то компоненте я пытаюсь определить действия

 methods: {
  ...mapActions('rollout/site', [
      LIST_REQUEST
  ])
}
  

Здесь первая ошибка: rollout/site не найдена, потому что я предполагаю rollout , что это папка, а не модуль, и поэтому site это модуль, а не вложенный модуль rollout .

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

LIST_REQUEST — это действие, исходящее из types.js и определяется как:

 export const LIST_REQUEST = "rollout/site/LIST_REQUEST";

  

Итак, в site.js модуль, который я могу использовать как:

 const actions = {
    [types.LIST_REQUEST]: async ({ commit }, payload= {}) => {
        // your actions here...
    },
}
  

Поскольку я использую mapActions(), вместо отправки таких действий, как: this.$store.dispatch() Я могу напрямую сделать this.LIST_REQUEST()

 import {
  LIST_REQUEST
} from "@/store/types/rollout/site";

export default {
  name: "SiteList",
  created() {
    this.LIST_REQUEST()
  },
  methods: {
    ...mapActions('rollout/site', [
      LIST_REQUEST
    ])
  }
}
  

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

Как я могу исправить эти проблемы с помощью вложенных модулей и использовать index.js . Может быть, у меня в голове небольшая путаница, не могли бы вы помочь прояснить эти понятия?

Ответ №1:

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

Ответ:

использовать

 modules: {
  core: {
    namespaced: true,
      modules {
        // Core modules
        country: coreCountry,
        region: coreRegion,
      }
  },
  rollout: {
    namespaced: true,
    modules: {
      // Rollout modules
      site: rolloutSite
    }
  }
}
  

(см. Объяснение ниже)

Если вы не вставите namespaced: true в свой coreCountry , coreRegion , и rolloutSite , это все равно будет похоже this.$store.dispatch(rollout/LIST_REQUEST) . Вставьте namespaced: true в них, если хотите this.$store.dispatch(rollout/site/LIST_REQUEST) , или, как вы сказали, this.LIST_REQUEST() с помощью

 methods: {
  ...mapActions('rollout/site', [
    LIST_REQUEST
  ])
}
  

Для ошибки с «LIST_REQUEST () не является функцией», возможно, это уже исправлено, но я подумал, что «развертывание / сайт / LIST_REQUEST» было странным именем для функции. Может быть, вы можете заставить определение действия работать, используя то, что у вас есть (возможно, поиграв с синтаксисом вокруг него, если он не работает?)

 const actions = {
    [types.LIST_REQUEST]: async ({ commit }, payload= {}) => {
        // your actions here...
    },
}
  

Но вместо этого я бы рекомендовал более распространенный способ (руководство Vuex также использует это) для определения действия:

 actions: {
  actionName (context, payload) {
    // async functions and commits here
  }
}
  

или

 actions: {
  actionName ({ state, rootState, commit, dispatch, getters, rootGetters }, payload) {
    // async functions and commits here
  }
}
  

Объяснение:

все, что входит в modules: { } , считается модулем, который по определению (определенному в ссылке на API Vuex) является объектом, который

 key: {
  // required (can be empty)
  state,

  // optional (as denoted by '?')
  namespaced?,
  mutations?,
  actions?,
  getters?,
  modules? // **nested modules go here**
}
  

Итак, внутри модулей нет понятия папок. Когда вы вставляете

 module {
  core: { ... },
  rollout: { ... }
}
  

core и rollout будут распознаны как модули, а не папки.

Итак, имея

 module {
  rollout: {
    site: { ... }
  }
}
  

не имеет никакого смысла. все, что находится внутри rollout (распознается как модуль), должно быть либо state: , , namespaced: , mutations: , actions: , getters: , либо modules: . Больше ничего.

Итак, чтобы вставить модуль внутри modules: { } , вы можете либо

  1. прямой список импортированных модулей (сохраните имя из инструкции import): modules: { coreCountry, coreRegion }
  2. список импортированных модулей, но переименованных: modules: { country: coreCountry, region: coreRegion }
  3. или определите модуль на месте (без импорта): как core: { module content here } и rollout: { module content here } в ответе, который я дал, или account в руководстве по vuex

По сути, для создания вложенных модулей вам просто нужно было вставить подмодули в modules: { } родительские модули (могут быть определены на месте, как в ответе, или быть созданы где-то еще и импортированы), например core , и rollout которые находятся в modules: { } корневом хранилище сами по себе.

Ответ №2:

Если вы хотите вложить модули и предоставить им собственное пространство имен, вы должны установить namespaced атрибут:

 export default new Vuex.Store({
  modules: {
    rollout: {
      namespaced: true,
      site: rolloutSite
    }
  }
})
  

При использовании mapActions помощника вам не нужно импортировать ничего, кроме самого помощника. Скажем, у этого rollout/site есть вызываемый метод foo , вы должны быть в состоянии просто сделать это:

 methods: {
    ...mapActions({ foo: 'rollout/site/foo' })
}
  

Комментарии:

1. При автоматической регистрации вложенных модулей с require.context помощью цикла и store.registerModule я использовал пустой объект в качестве целевого объекта для новых регистраций вложенных модулей, у которых еще не было существующего родителя, но пытался выяснить, почему он не зарегистрировался должным образом. Я добавил namespaced: true к этому пустому объекту, и теперь все работает так, как ожидалось! Это должно быть отмечено как ответ!