vuex 详解(2)
1. mutations 状态更新
-
vuex的store状态更新的唯一方式:提交mutation
(官方文档说明!!!) -
Mutation主要包括两部分:
- 字符串的事件类型(type)
- 一个回调函数(handler),该回调函数的第一个参数就是state
mutation定义方式:
mutation:{
increment(state){
state.counter++
}
}
//定义increment函数修改state中的数据
mutation更新方式:
increment(){
this.$store.commit('increment')
}
//在组件里面使用函数,实现state状态的改变
2. mutations 参数传递
- 需求:通过mutation传入参数,实现数据一次加5,一次加10
mutations定义函数:
mutations:{
incrementCount(state, count){
state.counter += count;
}
},
//除了传入状态state外,还传入了参数count
组件内mutation实现数据更新:
methods:{
incrementCount(count ){
this.$store.commit('incrementCount',count)
}
}
//然后@click = 'incrementCount(5)' 就可以实现需求
-
而加入我们想传递多于一个的参数呢?
这个时候我们会以对象的形式传递,也就是paylode是一个对象。
再从paylode读取我们想要的信息。 -
以对象的方式传递:
incrementCount(count ){
this.$store.commit({
type:'incrementCount',
count
})
},
- 调用:
incrementCount(state, payload){
state.counter += payload.count;
},
//通过payload.count 来读取相应的数据
3. mutations 代码风格优化
- 普通风格
methods:{
incrementCount(count ){
this.$store.commit('incrementCount',count)
}
}
- 特殊风格
methods:{
incrementCount(count ){
this.$store.commit({
type:'incrementCount',
count
})
}
}
这种方式传递过去的count将会是一个对象,确切的说他就是payload,是一个对象,而如果你要使用count的话应该这样使用:
mutations:{
incrementCount(state, payload){
state.counter += payload.count;
}
},
4.响应式原理
- vue官方明确定义,vuex实现响应式的最基本要求是,state状态定义了变量,才可以实现数据的响应式。
- 举个例子:
state:{
info:{
name:'康家豪',
age:20,
lab:'xiyounet'
}
}
//现在在state中定义一个info数据,info中定义了name,age,lab属性。
先将数据渲染在组件的页面内,再通过按钮点击事件,我将对info数据进行修改:
mutations:{
changeInfo(state){
state.info.name = 'kangjiahao',
state.info.age = 100,
state.info.lab = 'netxiyou'
//注意:因为我的name, age ,lab 属性都已经再state中定义过了,所以修改后,页面View层中的数据就会实现响应式更新。
state.info['address'] = 'home'
//这个数据就不会实现响应式渲染在页面上因为他没有再state中定义,不能实现响应式。
}
}
-
那么我如何实现没有在state中定义过的状态以响应式的方式渲染在页面上呢?
-
vue.set() 响应式控制数据,
调用方法:Vue.set( target, key, value )
target:要更改的数据源(可以是对象或者数组)
key:要更改的具体数据
value :重新赋的值 -
vue.delete() 响应式删除数据
调用方法:Vue.set( target, key, )
target:要更改的数据源(可以是对象或者数组)
key:要更改的具体数据
mutations:{
changeInfo(state){
vue.set(state.info,'address','home')
//vue.set() 实现将数据以响应式的方式渲染在组件内
state.info['address'] = 'home'
//响应式删除
Vue.delete(state.info,'age')
//vue.delete
}
}
5.mutations同步函数和异步函数的区别
- mutations同步函数 (为什么要用到actions)
(vue官方文档说明 mutation中函数最好为同步函数)
因为我们使用了devtools工具来跟踪状态的改变,所以当mutation函数为同步状态时
//devtools中数据 原始数据
baseState{
info:Object
name:"康家豪"
age:20
slab:"xiyounet"
}
执行xiugai函数:
xiugai(state){
state.info.name = 'kangjiahao',
state.info.age = 100,
state.info.lab = 'netxiyou'
}
//devtools中数据 修改数据
xiugai{
info:Object
name:"kangjiahao"
age:100
lab:"netxiyou"
//数据发生了实时的改变,
}
-
那么问题来了,因为我们使用了devtools开发工具,mutations中使用异步函数函数会让我们无法跟踪state状态的改变。因为state中的数据和页面响应的数据不一致
-
而如果我使用异步函数:
xiugai(state){
setTimeout(()=>{
state.info.name = 'kangjiahao',
state.info.age = 100,
state.info.lab = 'netxiyou'
},1000)
}
这个时候devtools中数据原始数据和修改后的info中是一样的,但是数据已经更新了。这就让我们无法再devtools中跟踪state状态
以上数据均在devtools中查看
6.actions的使用
vue官方文档强调,不要在Mutation中进行一些异步操作,比如网络请求,必然是异步的,时候怎么处理呢?
Actions类似于Mutations,但是用来代替Mutation继续异步操作的。
- Action的使用:
//在mutations中定义函数 xiugai ,在actions中异步使用
//函数xiugai
xiugai(state){
state.info.name = 'kangjiahao',
state.info.age = 100,
state.info.lab = 'netxiyou'
}
//actions异步使用xiugai
actions:{
UpData(context){
setTimeout(()=>{
context.commit('xiugai')
})
}
},
// 将修改绑定到元素身上。
xiugai(){
this.$store.dispatch('UpData')
}
这样使用devtools中的state状态也会实时发生改变。
- actions也可以传参
actions:{
xiugai(context,payload){
setTimeout(()=>{
context.commit('xiugai',payload)
console.log(payload)
})
}
},
- 上面这种方式只能解决传递一个参数,那么如果我要传递两个参数呢?
使用promise方法:超级优雅的代码
actions:{
xiugai(context,payload){
return new Promise((resolve, reject)=>{
setTimeout(()=>{
context.commit('xiugai',payload)
resolve(payload);
},2000);
})
}
},
xiugai(){
this.$store
.dispatch('xiugai','我是携带的信息')
.then(res=>{
console.log('里面完成了提交');
console.log(res);
})
}
//在action中return一个promise对象,在修改函数中,.then返回结果和下一步操作
- 注意actions中不在使用commit而是使用dispatch
7.modules的使用
- question one
vue官方文档不是推荐单一状态树嘛!!!
那么为什么我们在vuex中使用模块呢?
vue推荐我们使用单一状态树,也就意味着很多状态都会交给vuex来管理。
当应用变得非常复杂时,store对象就有可能变得非常臃肿
为了解决这个问题,vuex允许在module中让我们可以去划分新的module,
新的module可以有state,mutations,actions,getters,以及新的module
+基本代码演示
const moduleA = {
state:{},
mutations:{},
actions:{},
getters:{},
modules:{}
}
const store = new Vuex.Store({
state:{},
mutations:{},
actions:{},
getters:{],
modules:{
a:moduleA
}
})
- 那么新的moduleA中的数据如果我要渲染在页面上该怎么操作?
const moduleA = {
state:{
name:'康家豪2号'
},
mutations:{
changeData(state,payload){
state.name = payload
}
},
getters:{
fullName(state){
return state.name = state.name + '康家豪二号'
},
fullName2(state,getters){
return getters.fullName + '222';
},
fullName3(state,getters,rootState){
return rootState.counter;
}
},
actions:{
changeData2(context,payload){ //这里的context取到的是自己模块里面的mutations
setTimeout(()=>{
context.commit('changeData',payload)
},1000)
}
},
modules:{}
}
- 在相关组件中使用:
state数据使用: $store.state.a.name
我原本以为是这样的{{ $store.modules.a.state.name }}
然而是错的
正确的是这样的:{{ $store.state.a.name }}
vue会将你modules中的state放入最大的state总管的state里面
mutations,getters,actions,都和之前使用一样
8.store文件目录结构
- 可以把mutations, getters,actions,modules 抽离成一个js文件,
- 方便代码管理和后期维护。
- 而modules或许会有好几个模块,所以需要放在module文件夹下。
- 我的store文件的目录结构
嗯嗯 现在为止 基本 vuex 能掌握的都差不多了
————————————————————————————————————
我曾七次鄙视自己的灵魂:
第一次,当它本可进取时,却故作谦卑;
第二次,当它空虚时,用爱欲来填充;
第三次,在困难和容易之间,它选择了容易;
第四次,它犯了错,却借由别人也会犯错来宽慰自己;
第五次,它自由软弱,却把它认为是生命的坚韧;
第六次,当它鄙夷一张丑恶的嘴脸时,却不知那正是自己面具中的一副;
第七次,它侧身于生活的污泥中虽不甘心,却又畏首畏尾。
————————————————————————————————————