[鼠年全马] W39 - 使用Vuex管理资料状态(下)

这週要继续来探讨 Vuex
上週的文章传送门

首先先回顾一下上週提到的 Store 中有这些东西:

state: 存放资料状态的物件,类似Vue元件中的 dataactions: 存放方法的物件,类似Vue元件中的 methods
除了改变资料状态以外的工作,都会在这边处理mutations: 负责做改变资料状态的动作getters: 取得资料状态的方法,在取得之前也可以在这先做一些资料处理,类似Vue元件中的 computedmodules: 模组化的Vuex

#getters取得资料

还记得上週取得资料的时候,我们直接使用 $store.state 在 computed 中直接抓资料吗?

当资料需要被处理过的话,当然也可以从 computed 中进行处理,例如以上週的 TodoList 例子来说,假设我需要计算有几笔是已完成的,就可以这样写:

computed: {  countTodoDone() {    let todolist = this.$store.state.todolist;    return todolist.filter((item) => {      return item.done === true;    });  },},

那 getters 要干嘛xD?

当有多个地方需要用到相同的计算结果时,getters 就会现身~
而他的写法就跟 computed 一样:

getters: {  countTodoDone() {    let todolist = this.$store.state.todolist;    return todolist.filter((item) => {      return item.done === true;    });  },},

準备好 getters 之后,在元件中就能使用 mapGetters() 的方式来取得计算结果啰~

//元件中先 import 它import { mapGetters } from "vuex";export default {  ...,  computed: {    ...mapGetters(["countTodoDone"]),  },};

如果有多个 getters 要取得,就直接加在阵列中就好:

...mapGetters(["countTodoDone", "AAA", "BBB"]),

#模组化

在大型专案中,不可能只存在一个元件,当有多个元件都要存取 Store,这时候就会容易发生冲突的状况
例如取了一样的资料名称或是方法名称等等

这时候就可以将 Store 进行模组化 modules ,分割成多个模组来解决这个困境

由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常複杂时,store 对象就有可能变得相当臃肿。
为了解决以上问题,Vuex允许我们将store分割成模块(module)。

而分割出来的每一个模组都各自包含自己的:

stateactionsmutationsgetters

官网的模组化範例是这么写的:

const moduleA = {  state: () => ({ ... }),  mutations: { ... },  actions: { ... },  getters: { ... }}const moduleB = {  state: () => ({ ... }),  mutations: { ... },  actions: { ... }}const store = new Vuex.Store({  modules: {    a: moduleA,    b: moduleB  }})store.state.a // -> moduleA 的状态store.state.b // -> moduleB 的状态

可以看到範例中 moduleA 和 moduleB 各自有自己的内容,最后放进 Store 的 modules

不过我的观念是不会把模组和 Store 写在一起,因为这样全挤在一坨很噁心而且不好维护~
那要怎么写呢?

我们拿昨天的 TodoList 来改改看吧~

#Step 1

首先,在 /store 资料夹里面新增一个档案 - todolist.js

src└── store    ├── index.js    └── todolist.js //新增这个档案

#Step 2

模组中该有的基本内容都加上去:

import Vue from 'vue'import Vuex from 'vuex'Vue.use(Vuex)export default {    state: { },    actions: { },    mutations: { },    getters: { }};

注意这边汇出(export)的不是 Store 喔!!
有些菜鸟没注意到 (就是我)

#Step 3

把跟 TodoList 相关的内容全部移植过去:

export default {    state: {        todolist: [            { id: 1, todo: "交女朋友", done: false },            { id: 2, todo: "财务自由", done: false },            { id: 3, todo: "当码农", done: true },        ],    },    actions: {        todoDone(context, { id, done }) {            context.commit('TODOLIST', { id, done });        },    },    mutations: {        TODOLIST(state, { id, done }) {            state.todolist.find((item) => {                return item.id === id            }).done = done;        },    },    getters: {        countTodoDone() {            let todolist = this.$store.state.todolist;            return todolist.filter((item) => {                return item.done === true;            });        },    }};

#Step 4

在 /store/index.js 主档中引用 todolist.js:

import TodoListModules from './todolist'

并且加进 modules:

export default new Vuex.Store({    ...,    modules: {        RoomsModules,        TodoListModules,    },});

#Step 5

开启 App.vue 在取得 Store 资料的部分要稍做修改

myTodo 加上模组的部份
computed: {  myTodo() {    return this.$store.state.TodoListModules.todolist;  },},

到这边暂停一下,这里模组化的内容中
state 是注册在 TodoListModules 命名空间中
而其他的 actions & mutations & getters 则是注册在全局命名空间

所以会发现就算 todoDone() 不加上模组也能呼叫:

methods: {  todoDone(id, done) {    this.$store.dispatch("todoDone", { id, done });  },},

#Step 6

官方是这么说明的:

默认情况下,模块内部的action、mutation和getter是注册在全局命名空间的——这样使得多个模块能够对同一mutation或action作出响应。
如果希望你的模块具有更高的封装度和复用性,你可以通过添加namespaced: true的方式使其成为带命名空间的模块。
当模块被注册后,它的所有getter、action及mutation都会自动根据模块注册的路径调整命名。

意思就是如果想让模组完整度高一点,可以加上 namespaced: true 这个属性,我们来加看看吧~

// /store/todolist.jsexport default {    namespaced: true,    ...,};

这时候点清单会发现console跳错啰!!

///[vuex] unknown action type: todoDone

回到 todoDone() 来加上模组,就又正常啰~

methods: {  todoDone(id, done) {    this.$store.dispatch("TodoListModules/todoDone", { id, done });  },},

到这就大功告成~ 完美移植TodoList模组化~
可以看一下画面一样可以动 哈哈xD
gif已死QQ


目前我研究到这而已~
已经可以把很多现有的专案改良了!!

其他功能,之后如果有再深入探讨的话再来发一篇吧~
http://img2.58codes.com/2024/emoticon29.gifhttp://img2.58codes.com/2024/emoticon29.gifhttp://img2.58codes.com/2024/emoticon29.gif


关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章