为大规模 Vue.js 应用程序构建 Vuex 存储
所有大型 Vue.js 应用程序的核心都是存储所有数据的存储。Vuex 存储作为 Vue.js 应用程序中的单一数据源,提供开箱即用的卓越性能和响应能力。随着应用程序复杂性和代码的增长,Vuex 存储很容易变得混乱,难以管理。根据最佳实践来构建应用程序的状态管理架构,可以解决大多数随着复杂性增长而出现的问题。
在本篇博文中,我们将讨论在大规模 Vue.js 应用程序中构建状态管理的一些最佳实践和技巧。我们将涵盖以下 5 个概念,以帮助您更好地构建商店。
- 构建商店
- 模块化商店
- 自动导入模块
- 重置模块状态
- 全局模块状态重置
1. 构建商店
Vuex 存储包含 4 个主要组件:
- 状态对象
- Getter 函数
- 行动
- 突变
如果您还不熟悉这四个概念,下面是上述内容的快速分解。状态对象将应用程序的数据保存为大型 JSON。Getter函数可帮助您在存储外部访问这些状态对象,它们可以充当响应式计算属性。突变,顾名思义,用于修改/突变状态对象。动作与突变非常相似,但动作不会突变状态,而是提交突变。动作可以包含任意异步代码或业务逻辑。
Vuex 建议仅在 Mutation 函数内修改状态对象。此外,由于 Mutation 函数本质上是同步的,因此建议不要在 Mutation 函数内运行任何繁重或阻塞的代码。相反,我们应该使用 Actions,这些 Actions 应该设计为异步的,用于执行所有繁重的负载或发出网络请求并提交修改。Actions 也是保存业务逻辑和数据处理逻辑的最佳位置。由于 Actions 可以将数据存储回 store,也可以用于将数据直接检索到 Vue 组件中,因此非常适合此类用例。
最好不要直接访问状态对象,而是使用 Getter 函数。Getter 函数可以作为mapGetters
计算属性轻松地映射到任何 Vue 组件中。
2. 商店模块化
难怪随着规模和复杂性的增加,store 会变得杂乱无章、难以理解。Vuex 提供了开箱即用的功能,可以根据您的应用程序将 store 拆分为具有特定用途的独立模块。借助 store 模块区分业务逻辑可以提高应用程序的可维护性。因此,我们需要确保每个模块都具有命名空间,并且不要使用全局 store 作用域来访问它们。
这是编写商店模块以及如何组合主商店中的所有模块的简单示例。
目录结构
store/
├── index.js ---> Main Store file
└── modules/
├── module1.store.js
├── module2.store.js
├── module3.store.js
├── module4.store.js
├── module5.store.js
└── module6.store.js
请注意,每个模块都命名为 ModuleName.store.js,这将帮助我们自动导入这些模块,我们将在下一节讨论它。
创作模块
我们可以将网络调用移到一个单独的 JavaScript 文件中,我们将在另一篇关于构建应用程序网络层的博客文章中讨论这个问题。为了便于阅读,我们甚至可以将状态对象、getter、action 和 mutations 分离到单独的文件中。如果 store 仍然庞大而复杂,最好将所有相关函数放在一起,并进一步将其模块化。
/* Module1.store.js */
// State object
const state = {
variable1: value,
variable2: value,
variable3: value
}
// Getter functions
const getters = {
getVariable1( state ) {
return state.variable1;
},
getVariable2( state ) {
return state.variable2;
},
....
}
// Actions
const actions = {
fetchVariable1({ commit }) {
return new Promise( (resolve, reject) => {
// Make network request and fetch data
// and commit the data
commit('SET_VARIABLE_1', data);
resolve();
}
},
....
}
// Mutations
const mutations = {
SET_VARIABLE_1(state, data) {
state.variable1 = data;
},
SET_VARIABLE_2(state, data) {
state.variable2 = data;
},
....
}
export default {
namespaced: true,
state,
getters,
actions,
mutations
}
组合模块
/** store/index.js **/
import Vue from 'vue';
import Vuex from 'vuex';
import createLogger from 'vuex/dist/logger';
import Module1 from './modules/module1.store';
import Module2 from './modules/module2.store';
...
Vue.use(Vuex);
const debug = process.env.NODE_ENV !== 'production';
export default new Vuex.Store({
modules: {
Module1,
Module2,
...
},
strict: debug,
plugins: debug? [ createLogger() ] : [],
}
3.自动导入商店模块
正如我提到的,如果模块变得越来越复杂,我们需要进一步将它们拆分成单独的模块以降低复杂性。当模块数量增加时,单独管理这些模块并手动导入每个模块会变得非常困难。我们将在 modules 子目录中创建一个小型 JS 文件来帮我们完成这项工作。这个文件将负责将所有模块整合在一起。
为了实现这一点,建议遵循严格的模块文件命名模式。毕竟,标准的命名模式将提高整个项目的可维护性。为了方便起见,我们的模块可以使用驼峰命名法(camelCase)加上 .store.js
扩展名来命名。例如,userData.store.js
我们需要index.js
在 modules 子目录中添加一个文件来查找所有这些模块并将它们导出到主存储中。
store/
├── index.js ---> Main Store file
└── modules/
├── index.js --> Auto exporter
├── module1.store.js
└── module2.store.js
自动导出脚本
/**
* Automatically imports all the modules and exports as a single module object
*/
const requireModule = require.context('.', false, /\.store\.js$/);
const modules = {};
requireModule.keys().forEach(filename => {
// create the module name from fileName
// remove the store.js extension and capitalize
const moduleName = filename
.replace(/(\.\/|\.store\.js)/g, '')
.replace(/^\w/, c => c.toUpperCase())
modules[moduleName] = requireModule(filename).default || requireModule(filename);
});
export default modules;
现在,我们的自动导出脚本已经到位,我们可以将其导入主商店并访问所有模块。
import Vue from 'vue'
import Vuex from 'vuex'
import createLogger from 'vuex/dist/logger'
// import the auto exporter
import modules from './modules';
Vue.use(Vuex);
const debug = process.env.NODE_ENV !== 'production';
export default new Vuex.Store({
modules, // all your modules automatically imported :)
strict: debug,
plugins: debug ? [createLogger()] : [] // set logger only for development
})
在主商店中使用自动导入器后,所有添加到 modules 子目录的新模块都将被自动导入。例如,如果您有一个名为 的文件user.store.js
,它将被导入为一个命名空间为 的商店模块User
。您可以使用这个命名空间将 Getters 和 Actions 映射到您的组件中,使用mapGetters
和mapActions
。
4. 重置模块状态
如果您曾经使用过 Vue+Vuex 应用程序,这些应用程序在 store 模块中管理大量数据,那么您可能遇到过需要重置 store 状态的情况。在应用程序中进行用户身份验证时,使用重置功能是很常见的,这样您就可以在用户注销时重置 store。
要重置 store,我们需要将状态对象分离为初始状态,并将其复制到主状态。我们可以使用一个返回初始状态的简单函数来实现这一点。因此,在 store 模块中,创建一个名为 的函数,initialState()
该函数返回实际的状态对象。
const initialState = () => ({
variable1: value,
variable2: value,
variable3: value
});
const state = initialState();
现在我们有了一个独立的初始状态,任何对状态的修改都不会影响实际的初始值。因此,我们可以用它来重置 store。创建一个变异函数,基本上用初始状态来变异整个 store 对象。
const initialState = () => ({
variable1: value,
variable2: value,
variable3: value
});
const state = initialState();
// Getters
// Actions
// Mutations
const mutations = {
RESET(state) {
const newState = initialState();
Object.keys(newState).forEach(key => {
state[key] = newState[key]
});
},
// other mutations
}
一旦我们有了 RESET 突变,我们就可以使用此功能通过调用操作或直接提交 RESET 突变轻松地重置存储。
// Actions
const actions = {
reset({ commit }) {
commit('RESET');
},
}
5.全局模块状态重置
如果我们需要重置整个 store,包括所有模块,该怎么办?如果您已按照第 4 点和第 5 点在所有模块中设置了自动导入器和模块状态重置突变,我们可以在主 store 文件中执行以下操作,一次性重置所有模块。
import Vue from 'vue'
import Vuex from 'vuex'
import createLogger from 'vuex/dist/logger'
import modules from './modules';
Vue.use(Vuex);
const debug = process.env.NODE_ENV !== 'production';
export default new Vuex.Store({
modules,
actions: {
reset({commit}) {
// resets state of all the modules
Object.keys(modules).forEach(moduleName => {
commit(`${moduleName}/RESET`);
})
}
},
strict: debug,
plugins: debug ? [createLogger()] : [] // set logger only for development
});
请注意,我们创建的操作位于主 store 文件中,而不是任何模块中。您可以使用以下代码行在 Vue 组件的任何位置触发此操作。
this.$store.dispatch('reset');
下一步是什么?
喜欢这篇文章吗?点赞并关注,即可随时掌握最新动态。在我们即将发布的博客文章中,我们将深入探讨如何构建 Vue.js 应用程序的网络功能。我们将介绍用于管理网络请求中的身份验证凭据、拦截器和错误处理的技术。
为了更好地了解我们在Locale.ai所做的工作,请在此处阅读有关地理空间分析的未开发领域的更多信息。
特别感谢Chris Fritz的精彩演讲《Vue 顾问不想让你知道的 7 个秘密模式》,这给了我们在本文中使用的一些想法。
大家好!我是 Locale.ai 的用户体验工程师,致力于为 B2B 客户解决地理空间问题。如果您热爱为用户解决用户体验问题,热爱设计,并希望与一支充满热情的团队合作,请查看 Locale 的职位空缺。想聊聊吗?您可以在Twitter、Instagram和GitHub
上找到我。
最初发布于haxzie.com
文章来源:https://dev.to/localeai/architecting-vuex-store-for-large-scale-vue-js-applications-4f1f