关于 state

每个vuex 应用只有一个 store 实例,所以使用起来不会太复杂,对于定位错误状态和操作会很方便。

简单用法:在vuex 的计算属性中返回vuex 的状态

最基本的使用方式,通过在vue文件里面初始化 vuex 的 store 来进行操作 vuex 的数据:如下例子:

 // 在组件里面使用 vuex
// 初始化 vuex 实例
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment: state => state.count++,
decrement: state => state.count--
}
}) // 创建一个 Counter 组件
const Counter = {
template: `<div>{{ count }}</div>`,
computed: {
count () {
// 直接返回 state
return store.state.count
}
}
} // 初始化 vue 实例
const app = new Vue({
el: '#app',
components: { Counter },
template: `
<div class="app">
<button @click="increment">+</button>
<button @click="decrement">-</button>
<counter></counter>
</div>
`
,
methods: {
increment () {
store.commit('increment')
},
decrement () {
store.commit('decrement')
}
}
})

每当 store.state.count 变化的时候, 都会重新求取计算属性,并且触发更新相关联的 DOM。
然而,这种模式导致组件依赖全局状态单例。在模块化的构建系统中,在每个需要使用 state 的组件中需要频繁地导入,并且在测试组件时需要模拟状态。
我以为,当项目发展到多个模块,多个组件和子组件混合的时候,在这种场合,单纯的值传递方式会很麻烦,因为组件或者模块之间的变量是独立的,对于一些全局使用的属性类似 token,cookie 之类的东西,或者是一些多个模块之间共享的属性。

所以 vuex 提供一个新的方式来将 vuex 的 store 存放到根组件下,通过 store 选项,将store从根组件“注入”到每一个子组件中(需调用 Vue.use(Vuex)):

 // 初始化 vuex的 store(可以将这个放到其他文件里面去)
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment: state => state.count++,
decrement: state => state.count--
}
}) // 在初始化 vue的时候注册 store(store 即是 vuex 的 store)
const app = new Vue({
el: '#app',
// 把 store 对象提供给 “store” 选项,这可以把 store 的实例注入所有的子组件
store,
components: { Counter }, // 子组件
template: `
<div class="app">
<counter></counter>
</div>
`
})

通过在根实例中注册 store 选项,该 store 实例会注入到根组件下的所有子组件中,且子组件能通过 this.$store 访问到。让我们更新下 Counter 的实现:

 // 这是子组件 Counter
const Counter = {
template: `<div>{{ count }}</div>`,
computed: {
count () {
// 通过this.$store能够访问到 store 并且获取到 state
return this.$store.state.count
}
}
}

通过这种方式可以在实际应用中,将 vuex 的初始化分离出去其他模块化文件,然后在 vue初始化的引用相关 vuex 的文件即可,然后通过this.$store全局调用 vuex 的 store 来实现数据存储。
我整理了一下完整的例子,这是 jsrun的例子:
http://jsrun.net/qWqKp
高级用法:mapState 辅助函数
当一个组件需要获取多个状态时候,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,我们可以使用 mapState 辅助函数帮助我们生成计算属性,让你少按几次键。(其实就是自动转换了一些语法输出)
import { mapState } from 'vuex'需要先引入才可以使用
mapState使用前后对比:

 // 不使用mapState时:
computed: {
count () {
return this.$store.state.count
}
}
// 使用mapState时:
computed: mapState({
count: state => state.count,
})

如果在大批量的类似这种的计算属性的话,使用 mapState 会更加便捷,而且不只是普通字符串,函数也可以转换,确实是比较方便的。
这里会有一个疑问,mapState到底做了什么事情,怎么将代码转为 vue 能识别的代码?所以需要参考 vuex 源代码中关于mapState的部分:(我找了当前 vuex 版本3.01的源代码:https://github.com/vuejs/vuex/blob/e821f1bf5b818992d7f34c03029ce2ded1f52a75/dist/vuex.esm.js)
这是normalizeMap的代码:

 function normalizeMap (map) {
// 判断是否数组,并且最终返回也是一个数组
return Array.isArray(map)
// 是数组就直接 map 循环
? map.map(key => ({ key, val: key }))
// 是对象就将 key拿出来,然后再进行 map 循环
: Object.keys(map).map(key => ({ key, val: map[key] }))
}

这是mapState的代码:

 var mapState = normalizeNamespace(function (namespace, states) {
var res = {}; // 这是一个对象类型
// 将 state 通过normalizeMap格式化变成一个数组,数组元素是一个对象
normalizeMap(states).forEach(function (ref) {
var key = ref.key;// 将数组元素对象解出来,先保存起来被后面使用
var val = ref.val;
// 组成一个新数组,以 key 为 key,值是一个函数mappedState
res[key] = function mappedState () {
var state = this.$store.state; // 将本身 vuex 的 store 的 state 和 getters 保存
var getters = this.$store.getters;
// 先不看 namespace 部分
// ......
// 这个函数里面会判断真正的值 ref.val 是函数还是普通值
return typeof val === 'function'
? val.call(this, state, getters) // 函数会被直接执行,并且传入 vuex 的state 和 getters
: state[val] // 值会直接放到 vuex 的state 里面
};
});
return res
});

states参数在这里只有2种,一种是对象{},一种是数组[]。因为normalizeMap只做了这2个判断。
states 会先通过normalizeMap进行序列化,转换为一个数组,数组元素是{ key, val: key } 这种结构的。
这里需要注意一下:如果传入的是对象里面只有函数,如下例的countPlusLocalState,那么被 object.keys获取的 key 是函数的名字。

 // 例如传入的state 是一个数组,如下:
[
{
count: state => state.count,
}
]
// 那么被normalizeMap转换后:
// 即转换为{ key, val: key })
[
{
key, // key 是对象{count: state => state.count}
val: key // val是对象{count: state => state.count}
},
//.....
] //------------------------ // 例如传入的state 是一个对象,如下:
{
count: state => state.count,
}
// 那么被normalizeMap转换后:
// 即被Object.keys(map).map(key => ({ key, val: map[key] }))处理后
[
{
key, // key 是count,因为被Object.keys提取出来
val: map[key] // val 是state => state.count,这里以 key 为键找对象的值
},
//.....
]

normalizeMap(states)格式化之后会使用 forEach 遍历这个数组:
如果 val 是一个函数,则直接调用这个 val 函数,把当前 store 上的 state 和 getters 作为参数,返回值作为 mappedState 的返回值。
否则直接把 this.$store.state[val]作为 mappedState 的返回值

 // 被 foreach 遍历,继续用上面的例子的state来举例,因为不是函数,所以被直接返回:
res["count"] = this.$store.state['state => state.count']
// 虽然这里是以数组的写法,但是在 js 里面数组的写法也可以用在对象上。
//如果是函数的话,会被执行val.call,并且传入了几个参数(this, this.$store.state, this.$store.getters)
res["countPlusLocalState"] = this.$store.state['state => state.count']

最终能够形成一个新的数组对象结构,并返回。
因为最终生成的数据就是 computed 的数据格式,所以直接将这个对象传给 computed 就可以直接使用了。
这是mapState经过源代码解析前和后的对比:

 // states 为对象时候,mapState转换前
computed: mapState({
count: state => state.count,
// 传字符串参数 'count' 等同于 `state => state.count`
countAlias: 'count',
// 为了能够使用 `this` 获取局部状态,必须使用常规函数
countPlusLocalState (state) {
return state.count + this.localCount
}
}) // states 为对象时候,mapState转换后
computed: {
count() {
// 直接转换为一般的计算属性的使用方式
return this.$store.state.count
},
countAlias() {
// 也是转为一般的计算属性的使用方式,只不过有指定名字的会使用中括号括起来
return this.$store.state['count']
},
countPlusLocalState() {
// 因为是函数,所以会被直接执行,并且传入了当前 store 上的 state 和 getters作为参数
//(但这里没使用 getters)
return this.$store.state.count + this.localCount
}
}

组件仍然保有局部状态
使用 Vuex 并不意味着你需要将所有的状态放入 Vuex。虽然将所有的状态放到 Vuex 会使状态变化更显式和易调试,但也会使代码变得冗长和不直观。如果有些状态严格属于单个组件,最好还是作为组件的局部状态。你应该根据你的应用开发需要进行权衡和确定。
关于 getter
Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性),就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。

 // 初始化 getter
const store = new Vuex.Store({
state: {
todos: [
{ id: 1, text: '...', done: true },
{ id: 2, text: '...', done: false }
]
},
getters: { // 这就是 getters
doneTodos: state => {
return state.todos.filter(todo => todo.done)
}
}
}) // 使用getter
store.getters.doneTodos // -> [{ id: 1, text: '...', done: true }]
// 或者可以this.$store.getters.xxxx 这样使用。
 // 可以在第二个参数里面传一个 getter 作为参数
getters: {
// ...
doneTodosCount: (state, getters) => {
// 传入了之前设置的doneTodos的 getters,所以直接使用了doneTodos
return getters.doneTodos.length
}
} store.getters.doneTodosCount // -> 1 // 让 getter 返回一个函数,来实现给 getter 传参。在你对 store 里的数组进行查询时非常有用。
getters: {
// ...
getTodoById: (state) => (id) => { // 返回一个函数
return state.todos.find(todo => todo.id === id)
}
} // 对返回的函数传入参数来使用
store.getters.getTodoById(2) // -> { id: 2, text: '...', done: false }

mapGetters 辅助函数

mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性。

参考 vuex 源代码,类似的处理也是跟...mapState类似:

 export function mapGetters(getters) {
const res = {}
// 先格式化,然后再处理
normalizeMap(getters).forEach(({key, val}) => {
res[key] = function mappedGetter() {
if (!(val in this.$store.getters)) {
console.error(`[vuex] unknown getter: ${val}`)
}
return this.$store.getters[val]
}
})
return res
}

相比 mapState 来说,他简单一点。
唯一的区别就是它的 val 不能是函数,只能是一个字符串,而且会检查 val in this.$store.getters的值,如果为 false 会输出一条错误日志。
关于三个点...mapstate 处理
其实三个点就是es6的扩展运算符。
可以将一个数组转为用逗号分隔的参数序列,也可以将对象进行展开,如果应用到 mapstate 身上就是:
需要注意:vue的 computed 是对象,里面的属性是对象属性。

 computed: {
// 一般 computed 对象属性
now: function () {
return Date.now()
}
// 使用对象展开运算符将此对象混入到外部对象中
...mapGetters([
'doneTodosCount',
'anotherGetter',
// ...
]) // 转换后是这样,跟一般 computed 对象属性差不多
doneTodosCount:function(){},
anotherGetter:function(){}
}

作者: whynotbetter 
链接:https://www.imooc.com/article/22673
来源:慕课网
本文原创发布于慕课网 ,转载请注明出处,谢谢合作

Vuex详解笔记2的更多相关文章

  1. Vuex详解笔记1

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

  2. TCP-IP详解笔记8

    TCP-IP详解笔记8 TCP超时与重传 下层网络层(IP)可能出现丢失, 重复或丢失包的情况, TCP协议提供了可靠的数据传输服务. TCP启动重传操作, 重传尚未确定的数据. 基于时间重传. 基于 ...

  3. TCP-IP详解笔记7

    TCP-IP详解笔记7 TCP: 传输控制协议(初步) 使用差错校正码来纠正通信问题, 自动重复请求(Automatic Repeat Request, ARQ). 分组重新排序, 分组复制, 分组丢 ...

  4. TCP-IP详解笔记6

    TCP-IP详解笔记6 用户数据报协议和IP分片 UDP是一种保留消息边界的面向数据报的传输层协议. 不提供差错纠正, 队列管理, 重复消除, 流量控制和拥塞控制. 提供差错检测, 端到端(end-t ...

  5. TCP-IP详解笔记5

    TCP-IP详解笔记5 ICMPv4和ICMPv6: Internet控制报文协议 Internet控制报文协议(Internet Control Message Protocol, ICMP)与IP ...

  6. TCP-IP详解笔记4

    TCP-IP详解笔记4 系统配置: DHCP和自动配置 每台主机和路由器需要一定的配置信息,配置信息用于为系统指定本地名称,及为接口指定标识符(如IP地址). 提供或使用各种网络服务,域名系统(DNS ...

  7. TCP-IP详解笔记3

    TCP-IP详解笔记3 地址解析协议 IP协议的设计目标是为跨越不同类型物理网络的分组交换提供互操作. 网络层软件使用的地址和底层网络硬件使用的地址之间进行转换. 对于TCP/IP网络,地址解析协议( ...

  8. http详解笔记

    http详解笔记 http,(HyperText Transfer Protocol),超文本传输协议,亦成为超文本转移协议   通常使用的网络是在TCP/IP协议族的基础上运作的,HTTP属于它的一 ...

  9. vue:vuex详解

    一.什么是Vuex? https://vuex.vuejs.org/zh-cn 官方说法:Vuex 是一个专为 Vue.js应用程序开发的状态管理模式.它采用集中式存储管理应用的所有组件的状态,并以相 ...

随机推荐

  1. Linux网络 - 数据包的接收过程【转】

    转自:https://segmentfault.com/a/1190000008836467 本文将介绍在Linux系统中,数据包是如何一步一步从网卡传到进程手中的. 如果英文没有问题,强烈建议阅读后 ...

  2. 新版本微信导致的ios表单bug

    解决方法如下: $(document).delegate('input, textarea, select', 'blur', function(){ setTimeout(function(){ $ ...

  3. Python3学习笔记04-运算符

    算术运算符 +     加两个对象相加 -      减得到负数或是一个数减去另一个数 *     乘两个数相乘或是返回一个被重复若干次的字符串 /     除x 除以 y %    取模返回除法的余 ...

  4. Flash芯片你都认识吗?

    [导读]Flash存储器,简称Flash,它结合了ROM和RAM的长处,不仅具备电子可擦除可编程的性能,还不会因断电而丢失数据,具有快速读取数据的特点;在现在琳琅满目的电子市场上,Flash总类可谓繁 ...

  5. cef_binary_3.2623.1401.gb90a3be

    这个资源现在很难搜索到 分享给大家 http://www.ceffans.com/forum.php?mod=viewthread&tid=9 http://pan.baidu.com/sha ...

  6. [转]POI大数据量Excel解决方案

    全文转载自:jinshuaiwang的博客 目前处理Excel的开源javaAPI主要有两种,一是Jxl(Java Excel API),Jxl只支持Excel2003以下的版本.另外一种是Apach ...

  7. python操作三大主流数据库(4)python操作mysql④python服务端flask和前端bootstrap框架结合实现新闻展示

    python操作mysql④python服务端flask和前端bootstrap框架结合实现新闻展示 参考文档http://flask.pocoo.org/docs/0.11/http://flask ...

  8. sql拼接显示table的多个列

    SELECT DeptName AS text,CONVERT(VARCHAR(10),ID)+','+DeptCode+','+ISNULL(Remark,'') AS tags,'' AS hre ...

  9. VUE 密码验证与提示

    1. 概述 1.1 说明 vue项目中,为了较为明了的让用户看到所输入的密码信息的长度与复杂度是否满足要求,开发一个组件来满足此需求(当密码输入时进行密码验证操作,当密码的长度在8到24位之间,密码中 ...

  10. python基础--压缩文件

    1)怎么压缩备份多个文件 使用zipfile 创建压缩文件 查看信息 解压缩 # 创建 import zipfile # os.chdir('test') my_zip = zipfile.ZipFi ...