#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: { }
, вы можете либо
- прямой список импортированных модулей (сохраните имя из инструкции import):
modules: { coreCountry, coreRegion }
- список импортированных модулей, но переименованных:
modules: { country: coreCountry, region: coreRegion }
- или определите модуль на месте (без импорта): как
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
к этому пустому объекту, и теперь все работает так, как ожидалось! Это должно быть отмечено как ответ!