Vuex
阅读数:192 评论数:0
跳转到新版页面分类
html/css/js
正文
一、概述
Vuex是一个专门为Vue.js应用程序开发的全局状态管理功能。它采用集中式存储管理应用的所有组件的状态, 并以相应的规则保证状态以一种可预测的方式发生变化。
每一个Vuex应用的核心就是store(仓库)。 “store”基本上就是一个容器, 它包含着你的应用中大部分的状态(state).Vuex和单纯的全局对象有以下两点不同:
(1) Vuex的状态存储是响应式的。 当Vue组件从store中读取状态的时候, 若store中的状态发生变化, 那么相应的组件也会相应地得到高效更新。
(2)你不能直接改变store中的状态。 改变store中的状态的唯一途径就是显式地提交mutation。 这样使我们可以方便的跟踪每一个状态的变化。
二、核心概念
1、State
Vuex使用单一状态树, 即每个应用将仅仅包含一个store实例。
Vuex通过store选项, 提供了一种机制将状态从根组件注入到每个子组件中(需要调用Vue.use(Vuex)),
通过在根实例中注册store选项, 该store实例会注入到根组件下的所有子组件中, 且子组件能通过this.$store访问到。
(1)mapState辅助函数
当一个组件需要获取多个状态时候, 将这些状态声明为计算属性会有些重复和冗余。为了解决这个问题, 我们可以使用mapState辅助函数帮助我们生成计算属性。
(2)对象展开运算符
2、Getter
Vuex允许我们在store中定义“getter”(可以认为是store的计算属性)。就像计算属性一样, getter的返回值会根据它的依赖被缓存起来, 且只有当它的依赖值发生了改变才会被重新计算。
(1)通过属性访问
(2)通过方法访问
也可以通过让getter返回一个函数, 来实现给getter传参。在对store里的数组进行查询时非常有用。
getter在通过方法访问时,每次都会进行调用,而不会缓存结果。
(3)mapGetters辅助函数
mapGetters辅助函数仅仅是将store中的getter映射到局部计算属性。
3、Mutation
使用Mutation改变状态的好处是,集中的一个位置对状态修改,不管在什么地方修改,都可以追踪到状态的修改,可以实现高级的time-travel调试功能。
Vuex中的mutation非常类似于事件:每个mutation都有一个字符串的事件类型(type)和一个回函数(handler)。这个回调函数就是我们进行状态更改的地方。
要唤醒一个mutation handler, 你需要以相应的type调用store.commit方法:
(1)payload
可以向store.commit传入额外的参数
大多数情况下, payload应该是一个对象。
(2)对象风格的提交方式
当使用对象风格的提交方式, 整个对象都作为payload传递给mutation函数。
(3)mutation必须是同步函数
(4)在组件中提交Mutation
可以在组件中使用this.$store.commit('xxx')提交mutation, 或者使用mapMutations辅助函数将组件中的methods映射为store.commit调用(需要在根节点注入store)
4、Action
Action提交的是mutation, 而不是直接变更状态。 Action可以包含任意异步操作。
Action函数接受一个与store实例具有相同方法和属性的context对象。
(1)分发action
(2)在组件中分发action
在组件中使用this.$store.dispatch('xxx')分发action, 或者使用mapActions辅助函数将组件的methods映射为store.dispatch调用(需要先在根节点注入store).
(3)组合action
store.dispatch可以处理被触发的action的处理函数返回的Promise, 并且store.dispatch仍然返回Promise:
现在你可以:
在另一个action中也可以:
如果我们利用async/await, 可以如下组合action:
5、module
由于使用单一状态树, 应用的所有状态会集中到一个比较大的对象。 当应用变得非常复杂时, store对象就有可能变得相当臃肿。
为了解决以上问题, Vuex允许我们将store分隔成模块(module)。 每个模块拥有自己的state、mutation、action、getter、甚至是嵌套子模块。
(1)模块的局部状态
对于模块内部的action, 局部状态通过context.state暴露出来,根节点状态则为context.rootState
对于模块内部的getter, 根节点状态会作为第三个参数暴漏出来:
(2)命名空间
默认情况下, 模块内部的action、mutation、getter是注册在全局命名空间的, 这样使得多个模块能够对同一mutation或action作出响应。
可以通过添加namespaced: true的方式使其成为带命名空间的模块。 当模块被注册后,它的所有getter、action及mutation都会自动根据模块注册的路径调整命名。
如果你希望使用全局state和getter, rootState和rootGetter会作为第三和第四参数传入getter, 也会通过context对象的属性传入action。
若需要在全局命名空间内分发action或提交mutation, 将{root:true}作为第三参数传给dispatch或commit即可。
若需要在带命名空间的模块注册全局action, 可添加root:true, 并将这个action的定义放在函数handler中。
这样所有绑定都会自动将该模块作为上下文,还可以通过使用createNamespacedHelpers创建基于某个命名空间辅助函数。
项目结构
示例:
Vuex并不限制你的代码结构, 但它规定了一些需要遵守的规则 :
1、应用层级的状态应该集中到单个store对象中。
2、提交mutation是更改状态的唯一方法, 并且这个过程是同步的。
3、异步逻辑都应该封装到action里面。
只要遵守以上规则 , 如何组织代码随便。 如果你的store文件太大, 只需将action、mutation和getter分割到单独的文件。
三、热重载
使用webpack的Hot Module Replacement API, Vuex支持在开发过程中热重载mutation、module、action和getter。你也可以在Browserify中使用browserify-hmr插件。
对于mutation的模块, 你需要使用store.hotUpdate()方法: