写点什么

Vuex 整洁架构之道

用户头像
devpoint
关注
发布于: 2021 年 04 月 11 日
Vuex整洁架构之道

如何保持 Vuex 架构的整洁和可维护,本文将探讨如何为 Vuex 创建整洁架构的技巧,这个架构的灵感来自于Vuex官方文档和互联网的其他 vuex 的学习资料。


本文中涉及的代码:https://github.com/QuintionTang/star-wars.git


之前也写过一遍关于 VUE 项目代码优化的文章《Vue 开发中可以使用的 ES6 新特征》。


Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。


为了简化起见,Vue 是一个采用基于组件的体系结构的框架,因此每个组件都被设计成一小块 Vue 文件,并可在组件之间重用。正因为如此,它并不排除某些小组件需要一起工作或使用相同数据的可能性。这就是为什么需要 Vuex 来解决这个问题。Vuex 就像一个全局变量和全局函数,拥有的每个组件都可以使用它。Vuex 更集中地管理 API 调用和存储响应数据,统一 API 调用的入口,这样一个 API 调用和数据就可以在 Vue 项目的每个组件中使用。



如何注册和创建 Vuex 模块

本文将使用 vuex 构建一个简单的 vue 应用程序,来显示《星球大战》电影中的人物和行星列表。



首先,需要基于每个作用域创建一个新的store module。下面是创建store module的模板。每个store module都包含statemutationsactions 和 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 modulestategettersactions)。而无需创建诸如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];    },};
复制代码

接下来就是actionsactions就像一个全局函数,可以在每个组件中调用。大多数情况下,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 应用程序的所有数据逻辑。必须确保它的整洁,以助于团队协作。

发布于: 2021 年 04 月 11 日阅读数: 20
用户头像

devpoint

关注

细节的追求者 2011.11.12 加入

专注前端开发,用技术创造价值!

评论

发布
暂无评论
Vuex整洁架构之道