Vuex整洁架构之道
如何保持Vuex架构的整洁和可维护,本文将探讨如何为Vuex创建整洁架构的技巧,这个架构的灵感来自于Vuex官方文档和互联网的其他vuex的学习资料。
之前也写过一遍关于VUE项目代码优化的文章《Vue 开发中可以使用的 ES6 新特征》
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
为了简化起见,Vue是一个采用基于组件的体系结构的框架,因此每个组件都被设计成一小块Vue文件,并可在组件之间重用。正因为如此,它并不排除某些小组件需要一起工作或使用相同数据的可能性。这就是为什么需要Vuex来解决这个问题。Vuex就像一个全局变量和全局函数,拥有的每个组件都可以使用它。Vuex更集中地管理API调用和存储响应数据,统一API调用的入口,这样一个API调用和数据就可以在Vue项目的每个组件中使用。
Github:https://github.com/QuintionTang/star-wars.git
如何注册和创建Vuex模块
本文将使用vuex构建一个简单的vue应用程序,来显示《星球大战》电影中的人物和行星列表。
首先,需要基于每个作用域创建一个新的store module
。下面是创建store module
的模板。每个store module
都包含state
, mutations
, actions
和 getters
。确保添加了namescaped
属性,避免store module
之间名称冲突,当然这也意味着访问store module
之前需要指定namescaped
名称,这样可以使得 Vuex 更加整洁和可维护。
const state = {}
const mutations = {}
const actions = {}
const getters = {}
export default {
namespaced: true,
state,
mutations,
actions,
getters,
};
创建完所需的store module
后,将所有的store module
合并到一个vuex store中。
实际项目中,可以直接在下面的代码中创建一个store module
(state
、getters
、actions
)。而无需创建诸如people
模块或planets
模块之类的单独模块。
为了达到架构清晰,建议不要那样做,最好创建几个小模块,并将其合并成一个vuex store中。
import Vue from "vue";
import Vuex from "vuex";
import people from "./modules/people";
import planets from "./modules/planets";
Vue.use(Vuex);
const store = new Vuex.Store({
modules: {
people: people, // 这种方式是可以重命名模块名称
planets,
},
});
export default store;
之后,将几个store module组合在一起,然后将其捆绑成一个module。下一步是创建Vue应用程序时注册它,以便Vue应用程序可以使用所有Vuex store moudle。
单个store module
在单独的store模块的其余部分中,仅关注people store module,因为在people与planets模块之间大部份是相似。
首先,从state开始,它就像一个包含数据的全局变量。在本文例子中,需要存储《星球大战》中的人物数据。因为有多个person数据,所以将其存储在一个数组中。在本例中,用空数组的默认值定义了一个people属性。其实state的设计有点像数据库的设计。
const state = {
people: []
}
其次,在想要存储的全局变量之后,接下来需要创建一个mutations
,以便能够修改状态值。因为它类似于一个全局变量,所以需要在不调用mutations
的情况下保护要编辑的state
,只有mutations
才能更改state
值。在本例中,在修改state
值时使用了(...
)展开操作符,在JavaScript中,如果只使用equals(=),则值只复制引用,而不是深入复制数组值。这很容易引起错误,以至于难以调试。因此,在改变新值时最好使用(...
)展开操作符。对于对象,也要确保使用(...
)展开操作符。
const mutations = {
setPeople(state, payload) {
state.people = [...payload];
},
};
接下来就是actions
,actions
就像一个全局函数,可以在每个组件中调用。大多数情况下,actions
用于处理API调用和更改state
值。在actions
中,通常是mutations
来改变state
的值。
在我看来,也是为了更整洁的构建。建议为API创建一个新的单独文件,本例中,将Axios的定义放在
api
文件夹中,接口方法放在services
中(意思是与服务器对接的方法)。
import axios from "axios";
const apiClient = axios.create({
baseURL: "https://swapi.dev/api/",
});
// interceptors 拦截器,统一处理接口的请求,如修改header等
apiClient.interceptors.request.use((request) => {
return request;
});
// interceptors 拦截器,统一处理接口的响应和错误
apiClient.interceptors.response.use(
(response) => {
return response;
},
(error) => {
console.error(error);
}
);
export default apiClient;
那么在services中,就是处理单个的方法。
import apiClient from "@/api";
const getPeople = (success, fail) => {
apiClient
.get("people")
.then((response) => success(response))
.catch((response) => fail(response));
};
const getPlanets = (success, fail) => {
apiClient
.get("planets")
.then((response) => success(response))
.catch((response) => fail(response));
};
export { getPeople, getPlanets };
在完成并准备好所有API调用及相应的调用方法后,现在回到的store module中。将定义的API方法与store module结合起来。
import * as services from "@/services";
const state = {
people: [],
};
const mutations = {
setPeople(state, payload) {
state.people = [...payload];
},
};
const actions = {
getPeople({ commit }, { success, fail } = {}) {
services.getPeople(
(response) => {
commit("setPeople", response.data.results);
success && success(response);
},
(response) => {
fail && fail(response);
}
);
},
};
const getters = {
male(state) {
return state.people.filter((person) => person.gender === "male") || [];
},
female(state) {
return (
state.people.filter((person) => person.gender === "female") || []
);
},
};
export default {
namespaced: true,
state,
mutations,
actions,
getters,
};
视图或组件调用store
首先,让从state
开始。要访问state
,需要从Vuex导入mapState
,并将其映射到一个computed
值,如下面的示例代码所示。
import { mapActions, mapState, mapGetters } from "vuex";
export default {
name: "People",
created() {
this.getPeople();
},
computed: {
...mapState("people", ["people"]),
...mapGetters("people", ["male", "female"]),
},
};
接下来就是actions
,需要从Vuex导入mapActions
并将其放置在方法中。
import { mapActions, mapState, mapGetters } from "vuex";
export default {
name: "People",
data() {
return {
loading: false,
};
},
created() {
this.loading = true;
this.getPeopleAction();
},
computed: {
...mapState("people", ["people"]),
...mapGetters("people", ["male", "female"]),
},
methods: {
...mapActions("people", ["getPeople"]), // 如果需要是多个namespace的方法,在下面在写一行
// ...mapActions("planets", ["getPlanets"]), // 此处为行星模块
handleSuccess() {
this.loading = false;
console.log("success fetch data");
},
handleFail() {
this.loading = false;
console.log("failed fetch data");
},
getPeopleAction() {
this.getPeople({
success: this.handleSuccess,
fail: this.handleFail,
});
// 下面注释的代码为优化前的调用方式
// this.$store.dispatch("people/getPeople", {
// success: this.handleSuccess,
// fail: this.handleFail,
// });
},
},
};
总结
Vuex是状态管理,它存储Vue应用程序的所有数据逻辑。必须确保它的整洁,以助于团队协作。