vue-状态管理vuex

当你读完这篇文章我想你也能看懂这张图了!

这篇文章主要是结合官方文档解读下vuex几个常用的概念:

一、安装及配置vuex

二、state

三、Getter

四、Mutation

五、Action

一、安装及配置vuex

首先来安装vuex:

npm install vuex --save

配置vuex

//创建store.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
//vuex实例化
const store = new Vuex.Store({
    state:{
       my_data:"lxc"
    },
    mutations:{
       name(val){
          state.my_data = val
       }
    }
})
export default store //导出配置

把vuex注入到vue根实例中

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store' //引入store.js 
Vue.config.productionTip = false

new Vue({
  router,
  store, //把vuex注册到根实例中 ,这样每个组件都可以使用vuex
  render: h => h(App),
}).$mount('#app')

核心store仓库:

每一个 Vuex 应用的核心就是 store(仓库)。“store”基本上就是一个容器,之所以这么说,我们打印store实例看下:

const store = new Vuex.Store({
    ··· ···
});
console.log(store)

 

vuex与其他单纯的全局对象不同点:

1 ·   vuex的状态存储是响应式的,当store中的数据发生变化,相对应的组件也会更新。

2 ·   更改store中状态(数据)的唯一途径要通过提交(commit)mutations的方式;通俗点说就是:通过mutations中的方法去更改store中的数据。

 

------------------------------------------------------------------------------------------------

 

二、state

简单说,state就是用来存储数据的:

const store = new Vuex.Store({
    state:{
        name:'lxc',
        age:20,
        address:'YanTai'
    },
    mutations:{
       ··· ···
    }
});

(1)vue组件中读取数据

1 >  this.$store.state.xxx

2 >  使用辅助函数mapState

在vue组件中获取vuex中的状态信息最简单的方法就是在计算属性中,通过this.$store.state.xxx来获取;之所以要在计算属性中获取数据,因为vuex的状态管理存储是响应式的,所以每次数据状态的变化,计算属性都能获取到最新的数据状态:

computed:{
   getStoreName(){
     return this.$store.state.name
   },
   getStoreage(){
     return this.$store.state.age
   },
   getStoreAddress(){
     return this.$store.state.address
   },
}

补充:

现在多数项目,vuex都会使用模块化,使用模块化时,我们在组件中使用如下方式获取:

this.$store.state.模块下的文件.属性

 如:下边需要获取module下的user.js文件中的state -> this.$store.user.xxx

mapState辅助函数

实际开发中,如果state中的包含多个数据状态,在计算属性中使用 this.$store.state.xxx 代码会有些重复、冗余!!!比如上边在计算属性中的代码。幸运的是vuex提供给我们一些辅助函数,帮助我们简化代码,mapState函数,返回到是一个对象,可以生成计算属性:

//store.js
const store = new Vuex.Store({
    state:{
        name:'lxc',
        age:20,
        address:'YanTai'
    },
    mutation:{
      ··· ···
    }
});
//在vue组件中:

//引入mapState辅助函数,它返回的是一个对象,下边是使用对象结构赋值的写法
import {mapState} from 'vuex'
export default {
    name:'home',
    data(){
        return{
            name:'鸡小西'
        }
    },
    computed:{
        otherComputed(){
            ··· ···
        },
        ...mapState({ 
            // 写法一:函数形式,在函数里可以使用this
            nameAlias(state){
                console.log(state) 
                return this.name +"+"+ state.name
            },
            //写法二:对象形式
            ageAlias:'age',
            addressAlias:'address'
        })
    },
}

上边代码,mapState返回的是一个对象,所以可以使用扩展运算符的写法,同时也很容易的将mapState混入(加到)计算属性computed中!!!获取store中的数据不再使用this.$store.state.xxx  ,  而是可以使用对象键值对的形式来获取store中的数据;也可以使用函数形式获取(使用函数优点在于:可以使用局部this,从而使用store中数据更加灵活!),参数state是一个包含在store中的所有数据对象:

补充:

如果vuex使用模块化,在组件中获取state属性:

const { mapState } from 'vuex'
export default {
    computed: {
        ...mapState({
            count: state => state.模块名.属性
        })
    }
}

------------------------------------------------------------------------------------------------

 

三、getter

通俗来说getter相当于store中的计算属性。

官方文档:有时候我们需要从store中派生出一些状态(也就是说store中的数据可以通过加工、过滤、重新计算等过滤出一些数据,供vue组件使用),这时getter上场了;

在store中使用getter最大的优点

(1)你可以在store中,集中处理数据,然后供给各个组件享用,而不需要在各个组件中分别来处理数据了!!!

(2)getter的返回值会根据它所依赖的数据进行缓存,只有依赖数据发生改变时才会重新计算!!!

const store = new Vuex.Store({
    state:{
      my_data:[
            {id:1,content:"吕星辰",status:true}
        ]
    },
    getters:{
        filterData:function(state){
            console.log(state)
            return xxxx
        }
    }
   ··· ···
})

上边代码,getters接受state作为第一个参数,与即将讲到的mutations一样,参数state是stroe中的所有数据。。。

获取gtter中的数据

与获取state中的数据相似,有两种方式:

(1)  this.$store.getters.xxx

(2)  使用辅助函数mapGetters

//使用this.$store.getters.xxx 获取gtters中的数据
computed:{
  getFilterData(){
     return this.$store.getters.xxx
  }
},
//使用辅助函数mapGetters来获取gtters中的数据
import {mapState,mapGetters} from 'vuex'
··· ···
computed:{
    //写法一:使用数组形式
   ...mapGetters([
       'filterData' //这个值是定义在getters中的属性
    ])
    //写法二:使用对象键值对形式,为数据起了一个别名
    ...mapGetters({
        dataAlias:'filterData' //这个值是定义在getters中的属性
    })
},

 

下边我们来看一个较完整的例子:在store中通过getter过滤掉status为false的数据,组件可以把getter中过滤掉的数据渲染到页面:

//store.js
const store = new Vuex.Store({
    state:{
        my_data:[
            {id:1,content:"吕星辰",status:true},
            {id:2,content:"鸡小西",status:true},
            {id:3,content:"王二胖",status:false},
            {id:4,content:"张大熊",status:true},
        ]
    },
    // 通过getter(计算属性)来过滤掉status为false的数据
    getters:{
        filterData:state=>{
            return state.my_data.filter(item=>item.status)
        }
    },
    mutation:{
      ··· ···
    }
});
<!--在组件中-->
<template>
  <div>
    <p>{{getFilterData}}</p> <!--数据渲染到页面-->
  </div>
</template>

<script>
export default {
    name:'home',
    computed:{
      //获取getter中的数据
      getFilterData(){
        return this.$store.getters.filterData
      }
    }
}
</script>

渲染结果:

 

------------------------------------------------------------------------------------------------

 

四、mutations  英文意思:突变、变化

想必对mutations都不是太陌生,对,没错!修改store状态的唯一方法就是通过提交mutations来实现 !!!

先来看下mutations

Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数。( 官方这句话我理解的意思是:在vue组件中修改store中的数据方法之一,需要使用 this.$store.commit( ' eventTypeName ' ),而这个字符串参数 就是事件类型同时也是回调函数的名子 

来看下官方文档中的例子,我又补充了一些代码:

//store.js
const store = new Vuex.Store({
  state: {
    count: 1
  },
  mutations: {
    increment (state) {
      // 变更状态
      state.count++
    }
  }
})
//vue组件中,通过this.$store.commit('xxx')来修改store中的数据
export default {
    name:'home',
    mounted(){
        this.$store.commit('increment')
    }
}

触发mutations中的回调函数有两种方式:

(1)  this.$store.commit.xxx

 在调用$store.commit时,除了参数一事件类型(就是回调函数名字)之外,还可以传第二个参数(官方叫提交载荷Payload),mutations 的回调函数第二个参数就是传过来的载荷Payload,通常情况下载荷Payload是一个对象:

//vue组件中
export default {
    name:'home',
    mounted(){
        //写法一:
       this.$store.commit('increment',{countParam:100})
        //写法二:对象格式的,type是必须包含的
       this.$store.commit({type:'increment',countParam:100})
    }
}
//store.js
const store = new Vuex.Store({
  state: {
    count: 1
  },
  mutations: {
    increment (state,param) {
      // 变更状态
      state.count += param.countParam 
    }
  }
})

上边代码,在vue组件中触发mutations中的回调函数,使用了2种方法传参;在vue-devtools中能清楚的看到,数据被修改了:

 

(2)  使用辅助函数mapMutations

与state、getter 类似,需要引入mapMutations 

import {mapState,mapGetters,mapMutations} from 'vuex'
methods:{
   ...mapMutations(
      //写法一:使用对象格式
      {add:'increment'}
      //写法二:使用数组格式
      ['increment']
   )
}

这里我着重说下使用 mapMutations如何传参

我们都知道使用  this.$store.commit( 'xxx' , params )  可以传递参数,但是很多人不知道使用mapMutations如何传递参数!!!首先要明白 使用 ...mapMutations(['increment' ])  里边的字符串参数会被挂载到vue实例上去,实际上它就是一个函数

export default {
    name:'home',
    mounted(){
        console.log(this)
    },
    methods:{
        ...mapMutations(['increment'])
    }
}

所以,如果你想使用mapMutations传递参数,你可以这样写:

export default {
    name:'news',
    data(){
      return{
        my_count:100
      }
    },
    //在钩子函数中,调用increment函数,括号中传递参数,这个参数会被mutations中回调函数的第二个参数接收
    mounted(){
       this.increment(this.my_count)
    },
    methods:{
       ...mapMutations(['increment'])
    }
}
//stroe.js
const store = new Vuex.Store({
    state:{
      count:1
    },
    mutations:{
      increment (state,param) {
        state.count += param
      }
    }
});

上边代码,在mounted钩子函数中,为inrement函数传递参数,我们在vue-devtools中查看修改结果:

使用mutation需要注意:

(1)最好提前在stroe中初始化好所有的属性。

(2)如果你想在对象上添加新属性或者修改对象时,有种方法:

  • 使用 Vue.set ( state , 'count' , '123' )  ;三个参数分别表示:在哪个对象中;要添加的属性;属性值是对少。。。

  • 以新对象替换老对象 (没看懂官方这个!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!)

(3)mutations中的函数必须是同步函数,原因是非常难调试,具体原因查看官方文档!

------------------------------------------------------------------------------------------------

 

五、Action 

先来看下官方文档:Action类似于mutation,不同的地方在于:

1、Action提交的是mutation(通俗点说就是修改的mutations中的状态),而不是直接修改state中的状态

2、Action可以包含任意异步操作(也就是说:在action中可以异步操作数据)

1、看下边官方案例,注册一个简单的action:

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    change(state) {
      state.count++
    }
  },
  actions: {
    change(context) {
      context.commit('change')
    }
  }
})

上边代码,Action中的函数接收了一个与store实例具有相同方法和属性的context对象( 也就是一个上下文对象,相当于this ),所以可以直接通过context来调用commit ( context.commit ( ) )来触发mutations中的方法。

在实际开发中,我们经常会用到结构赋值来简化代码,特别需要多次调用commit的时候:

const store = new Vuex.Store({
  ··· ···
  actions: {
    change({commit}) {
      commit('change')
    }
  }
})

上边代码,参数是用结构赋值的方式,这也是官方推荐的写法,刚开始没太明白为什么会这么写!后来把参数输出才恍然大悟!我们把context打印出来看下,结果是一个对象,所以用结构赋值获取对象的属性要用 { xxx }方式获取

actions:{
 change(context){
   console.log(context)
 }
}

 

2、触发action

再讲此问题之前,先说明下:为什么非要在  action 中 去触发mutations中的函数去修改数据呢,不如直接操作mutation多好?还记得 mutation 必须同步执行这个限制么?Action 就不受约束!

与前几个属性类似,在组件中触发action有两种方法:

(1)  this.$store.dispatch('xxx')

//在组件中
mounted(){
  //写法一:
  this.$store.dispatch('change',{count:10})
  //写法二:
  this.$store.dispatch({type:'change',count:10})
},
//store.js
const store = new Vuex.Store({
    state:{
      count:1
    },
    mutations:{
      increment(state,param){
         state.count += param
      }
    },
    actions:{
      change(context,countParam){
         context.commit('increment',countParam.count)
      }
    }
});

在vue-devtools中,可看到数据被修改:

(2) 使用辅助函数mapActions  

export default {
    name:'home',
    mounted(){
        console.log(this)
        this.addCount({count:100})
    },
    methods:{
        //mapActions中使用对象的形式
        ...mapActions(
            {addCount:'change'}
        )
    }
}

 

值得注意的是:上边代码,mapActions中使用对象格式,对象的key会被挂载到vue实例上去,就是一个函数,所以传递参数的时候应该调用this.addCount 

 

export default {
    name:'home',
    mounted(){
        console.log(this)
        this.change({count:100})
    },
    methods:{
        //mapActions中使用数组的形式
        ...mapActions(['change'])
    }
}

上边代码,mapActions中使用数组格式,字符串change会被挂载到vue实例上去,它就是一个函数,所以传递参数的时候应该调用this.change

 

3、Action异步流程(官方叫组合Action)

Action通常时候异步的,那么我们如何知道什么时候结束呢?你要明白的是action的处理函数返回的是一个promise对象,而且可以被store.dispatch( ) 处理,stroe.dispatch仍然返回一个promise对象:

下边使用官方文档的例子,模拟一个异步,在组件中可以监控、处理结果:

//stroe.js
actions: {
  change({ commit }) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        commit('someMutation') 
        resolve('成功')
      }, 1000)
    })
  }
}
export default {
  name:'home',
  mounted(){
    this.$store.dispatch('change').then((param)=>{
       console.log(param) //1秒后输出 "成功"
    })
  }
}

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值