vue状态管理器(vuex)

直接上示例,有不懂的可以查看vuex的官方文档:https://vuex.vuejs.org/zh/guide/state.html

一、state的用法

在src/vuex/index.js

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
// vuex是vue官方提供的用状态管理器,可以集中式的管理应用中所有的组件状态,更改数据的状态
// 更改vuex数据的方式;1.使用commit来触发mutations中的方法来更改数据的状态
//                    2.直接更改数据中的
const state = {   // state:store中存储的公共数据
    baseInfo:{  // state里面的数据可以直接通过接口获取
        name:'zhangsan',
        age:23

    }
}
const mutations = {  // mutations:用commit来触发mutations中的方法,从而触发数据更新
    changeName(state,value){
        state.baseInfo.name = value
    },
    changeAge(state,value){
        console.log(state)
        state.baseInfo.age += value
    }
}
// const commit = {}
const getters = {   // 通过state状态派生出其他依赖项
    changeAge:function(state){
        return state.baseInfo.age + 1
    }
}
const store = new Vuex.Store({
    state,
    mutations,
    getters
})  
export default store  // 导出store状态,方便的main.js中引入,

在main.js中使用:

import Vue from 'vue'
import App from './App.vue'
import store from './vuex/index'

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
  store   // 把 store 对象提供给 “store” 选项,把 store 的实例注入所有的子组件
}).$mount('#app')

在组件中使用:

<template>
  <div class="hello">
    {{this.$store.state.baseInfo.name}} <!-- 1.直接读取store中的state -->
    {{this.info.name}}     <!-- 2.读取计算属性 -->
    {{this.info.age}}
    <br>
    <button @click="chanAge">更改年龄</button>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  data(){
    return{
    }
  },
  computed:{
    info(){  // 将store中的baseInfo数据生成为计算属性,在view中可以直接使用{{this.info.name}}
    return this.$store.state.baseInfo
    }
  },
  methods:{
    chanAge(){   // 更改数据
this.$store.commit('changeAge',10)
    }
  }
}
</script>

 使用mapState生成计算属性:

<template>
  <div class="hello">
    {{this.info.name}}  <!--1.读取计算属性 -->
    <br>
    {{this.infoAlias.age}}  
    <br>    
    {{this.infoPlusLocalState}}
    <br>
<!-- 2.mapState传入字符串数组后可以这样使用 -->
    {{this.baseInfo.name +' 年龄:'+ this.baseInfo.age}}
<!-- 3.使用...将计算属性合并为一个对象 -->
    <br>
    {{this.Count}}
    <button @click="chanAge">更改年龄</button>
  </div>
</template>

<script>
import { mapState } from 'vuex'  // 从vuex中引入mapState方法
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  data(){
    return{
      localCount:100
    }
  },

  // 1.当组件需要获取多个状态时,一个个将其声明为计算属性会很重复和多余,可以用mapState辅助函数来帮我们生成计算属性
  computed:mapState({
    info:state => state.baseInfo,
    infoAlias: 'baseInfo',
    infoPlusLocalState (state) {
      return state.baseInfo.name + this.localCount
    }
  }),

// 2.当计算属性和state中的数据同名可以直接传入一个数组
computed:mapState(['baseInfo']),

  // 3.当组件中还有其他计算属性时,需要将state的计算属性和其他的计算属性合并为一个对象(mapState返回的是一个对象)
  // 此时就可以使用扩展运算符...
  computed:{
    Count(){
      return this.localCount + 'count'
    },
    ...mapState(['baseInfo'])
    },
  methods:{
    chanAge(){
      this.$store.commit('changeAge',10)  // 更改数据
    }
  }
}
</script>

总结state:在view中我们使用state有3种方式:

1.直接读取store中的数据:this.$store.state.baseInfo.name

2.将state生成计算属性:this.info.name

3.使用mapState生成计算属性,减少了代码的冗余:

this.infoAlias.age,
this.infoPlusLocalState,
this.baseInfo.name +' 年龄:'+ this.baseInfo.age

 二、getters的用法

getters可以被认为是store的计算属性,当多个组件都需要使用这个返回值时,就不需要在每个组件中都声明该计算属性;getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。

vuex/index.js 中加入getters

const getters = {   // 通过state状态派生出其他依赖项
    otherage:function(state){
        return state.baseInfo.age + 1
    },
    moreinfo:function(state,getter){  // 接收其他getter参与这个getter的运算
        return '姓名:'+ state.baseInfo.age + '年龄:'+ getter.otherage + 1
    },
    whileage:(state)=> function(id){
        return state.baseInfo.age + id
    },
}

组件中这样使用getters:

<template>
  <div class="hello">
    <!-- 组合式api --{{count}} -->
    <!-- 1.getter 在通过属性访问时是作为 Vue 的响应式系统的一部分缓存其中的。所以执行chanAge方法时,getter里面的值也会发生变化 -->

    {{this.otherage + this.moreinfo}}   
    <br>
    {{this.whileage}}  <!-- 2.getters通过方法访问 -->
    <br>
    <!-- 3.使用mapGetters -->
    {{this.whileage(20)}}-- {{this.comAge}}
    <button @click="chanAge">更改年龄</button>
  </div>
</template>

<script>
import { mapState,mapGetters } from 'vuex'
export default {
  name: 'HelloWorld',
  data(){
    return{
      localCount:100
    }
  },
  // 3.当组件中还有其他计算属性时,需要将state的计算属性和其他的计算属性合并为一个对象(mapState返回的是一个对象)
  // 此时就可以使用扩展运算符...
  computed:{
    Count(){
      return this.localCount + 'count'
    },
    // 1.通过属性访问
    otherage(){
      return this.$store.getters.otherage
    },
    moreinfo(){
      return this.$store.getters.moreinfo
    },
    // 2.通过方法访问
    whileage(){
      return this.$store.getters.whileage(20)
    },
    // 3.使用mapGetters将getter混入计算属性中
    ...mapGetters([
      'otherage','moreinfo','whileage'
    ]),
    // 4.给getter属性重命名,使用对象形式
    ...mapGetters({
      // 把 `this.comAge` 映射为 `this.$store.getters.otherage`
      'comAge':'otherage'
    }),
    ...mapState(['baseInfo'])
    },
  methods:{
    chanAge(){
      this.$store.commit('changeAge',10)  // 更改数据
    }
  }
}
</script>

总结getters:1.通过属性访问getter:

this.$store.getters.otherage

2.通过方法访问getter:

this.$store.getters.whileage(20)

3.通过mapGetters辅助函数:

...mapGetters([
      'otherage','moreinfo','whileage'
    ]),

三、Mutation的用法

改变vuex中store状态的唯一方法是提交mutation,mutations这个选项更像是事件注册,当我们需要使用mutations里面的事件时,需要调用store.commit方法来唤醒mutation handle

vuex/index.js 中修改mutations

const mutations = {  // mutations:用commit来触发mutations中的方法,从而触发数据更新
    changeName(state,res){  
        state.baseInfo.name = res.name
    },
    changeAge(state,res){
        state.baseInfo.age += res.value
    }
}

在组件中更改state的值:

<template>
  <div class="hello">
    {{this.$store.state.baseInfo.name}}   <!-- 直接读取store中的state -->
<!-- 1.直接使用commit提交 --> 
<button @click="chanAge">更改年龄</button>
<br>
<!-- 2.映射为methods中的方法进行提交 -->
<button @click="changeData(obj)">更改年龄</button>
<button @click="changeName(obj)">更改名字</button>
</div>
</template>
<script>
import { mapState,mapGetters,mapMutations }
from 'vuex'
export
default {
name:
'HelloWorld',
data(){
return{
  localCount:
100,
  obj:{
    value:
10, name:'lisi'
   }
  }
},
methods:{
chanAge(){
//this.$set(this.obj,'newVal',5)
// 1.提交mutation,并传参,通常以对象方式传参
//this.$store.commit('changeAge',{
// value:10
//})

this.$store.commit('changeAge',this.obj)
// 2.对象风格的提交方式(提交 mutation 的另一种方式是直接使用包含 type 属性的对象)
  this.$store.commit({
  type:
'changeAge', value:10
  })
},
// 3.使用mapMutations 将commit提交映射为methods中的方法
...mapMutations({
changeData:
'changeAge'
}),
...mapMutations([
'changeName','changeAge'
])
}
}
</script>

总结mutations:提交mutation的方式

1.使用commit提交:

this.$store.commit('changeAge',this.obj)
2.以对象方式风格提交:
this.$store.commit({
        type:'changeAge',
        value:10
      })
3.使用mapMutations:
...mapMutations([
      'changeName','changeAge'
    ])
特别注意:1.
2.mutations必须是同步函数,

 官网原话:每一条 mutation 被记录,devtools 都需要捕捉到前一状态和后一状态的快照。然而,在上面的例子中 mutation 中的异步函数中的回调让这不可能完成:因为当 mutation 触发的时候,回调函数还没有被调用,devtools 不知道什么时候回调函数实际上被调用——实质上任何在回调函数中进行的状态的改变都是不可追踪的。

所以如果mutation函数中是一个异步请求,比如在函数中我们调用了接口,我们无法追踪到什么时候接口调用完成

四、Actions的用法:
Actions类似于mutations,不同点在于:
  1.mutation是同步的,Action是异步的
  2.Action提交的是mutation,而不是直接更改状态
vuex/index.js 中添加actions

const mutations = {  // mutations:用commit来触发mutations中的方法,从而触发数据更新
    changeName(state,res){  
        state.baseInfo.name = res.name
    },
    changeAge(state,res){
        state.baseInfo.age += res.value
    },
    ALERTNAME(state,res){
        console.log(res)
        state.baseInfo.name += res.name
    }
}

const actions = {
    alertName(context,res){   // Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,通常会将context解构出来
        // 所以我们可以直接用context.getters,context.state;但ontext 对象不是 store 实例本身。
        context.commit('ALERTNAME',res)  // res要传给mutation函数
    },
    alertName2({commit},res){
        setTimeout(()=>{
            commit('changeAge',res)
        },2000)
        
        setTimeout(()=>{
            commit('ALERTNAME',res)
        },1000)
    },
}

在组件中派发action:

<template>
  <div class="hello">
    {{this.$store.state.baseInfo.name}}    <!--直接读取store中的state -->
  <!-- 1.分发action:通过action来提交mutation更改状态 -->
    <button @click="alertName">alertName</button>
    <br>
    <!-- 2.使用mapActions将组件的method映射为 this.$store.dispatch-->
    <button @click="alert1(obj)">alert</button>
    <br>
    <button @click="alertName(obj)">alertName1</button>
  </div>
</template>
<script>
import { mapState,mapGetters,mapMutations,mapActions } from 'vuex'
export default {
  name: 'HelloWorld',
  data(){
    return{
      localCount:100,
      obj:{
        value:10,
        name:'lisi001'
      }
    }
  },
 methods:{
    alertName(){
      // this.$store.dispatch('alertName',{
      //   name:'--action'
      // })
    // 使用actions的原因:action内部可以进行异步操作,而mutation只能是同步函数
      this.$store.dispatch('alertName2',{
        name:'--action2',
        value:5
      })
    },
    
    ...mapActions([
      'alertName',
      'alertName2'
    ]),
    ...mapActions({
      alert1:'alertName'
    })
  }
}
</script>

 组合Action

使用promise 、async/await 来组合Action,实现更多的异步操作

vuex/index.js 中添加actions

function getRes(){
    return {
        value:6,
        name:'await'
    }  
}

const mutations = {  // mutations:用commit来触发mutations中的方法,从而触发数据更新
    changeName(state,res){  
        state.baseInfo.name = res.name
    },
    changeAge(state,res){
        state.baseInfo.age += res.value
    },
    ALERTNAME(state,res){
        state.baseInfo.name += res.name
    }
}
const actions = {
    alertName(context,res){   // Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,通常会将context解构出来
        // 所以我们可以直接用context.getters,context.state;但ontext 对象不是 store 实例本身。
        context.commit('ALERTNAME',res)  // res要传给mutation函数
    },
    alertName2({commit},res){
        setTimeout(()=>{
            commit('changeAge',res)
        },2000)
        
        setTimeout(()=>{
            commit('ALERTNAME',res)
        },1000)
    },

    // 使用Promise组合action
    actionA({commit},res){
        return new Promise((resolve,reject)=>{
            if(res.value){
                commit('changeAge',res)
                resolve()
            }else{
                console.log('无传参!!!')
                reject()
            }
            
        })
    },
    actionB({dispatch,commit},res){
        return dispatch('actionA',res).then(()=>{
            commit('ALERTNAME',res)
        })
    },
    // 使用async/await 组合action
    async actionC({commit}){        
        commit('ALERTNAME',await getRes()) //getRes先执行 利用getRes得到res
    },
    async actionD({dispatch,commit},res){    
        await dispatch('actionA',res) // 等待 actionA 完成
        // await dispatch('actionA',res).then(()=>{
        //     console.log('actionA执行了')
        // })
        commit('ALERTNAME',await getRes()) // 利用getRes得到res
    }
}

在组件中使用如下:

<template>
  <div class="hello">
    {{this.$store.state.baseInfo.name}} 直接读取store中的state
    <!-- 1.分发action:通过action来提交mutation更改状态 -->
    <button @click="alertName">alertName</button>
    <br>
    <!-- 2.使用mapActions将组件的method映射为 this.$store.dispatch-->
    <button @click="alert1(obj)">alert</button>
    <br>
    <button @click="alertName(obj)">alertName1</button>

    <!-- 组合Action -- Promise -->
    <button @click="actionA(obj)">actionA - Promise</button>
    <button @click="actionB(obj)">actionB - Promise</button>
    <br>
    <!-- 组合Action -- async/await -->
    <button @click="actionC">actionC - async</button>
    <button @click="actionD(obj)">actionD - async</button>
  </div>
</template>
<script>
import { mapState,mapGetters,mapMutations,mapActions } from 'vuex'
export default {
  name: 'HelloWorld',
  data(){
    return{
      localCount:100,
      obj:{
        value:10,
        name:'lisi001'
      }
    }
  },
methods:{
// 组合Action -- promise
    actionA(obj){
      this.$store.dispatch('actionA',obj).then(()=>{
        console.log('age改变了')
      }).catch(()=>{
        console.log('age没改变')
      })
    },
    actionB(obj){
      console.log(this.$store.dispatch('actionB',obj))  //
      this.$store.dispatch('actionB',obj).then(()=>{
        console.log('name改变了')
      })
    },
    // 组合Action -- async/await
    actionC(){
      this.$store.dispatch('actionC')
    },
    actionD(obj){
      this.$store.dispatch('actionD',obj)
    }
  }
}
</script>

完整的vuex/index.js文件

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
// vuex是vue官方提供的用状态管理器,可以集中式的管理应用中所有的组件状态,更改数据的状态
// 更改vuex数据的方式;1.使用commit来触发mutations中的方法来更改数据状态
//                    2.派发action来提交mutation更改数据状态
function getRes(){
    return {
        value:6,
        name:'await'
    }  
}
const state = {   // state:store中存储的公共数据
    baseInfo:{  // state里面的数据可以直接通过接口获取
        name:'zhangsan',
        age:23

    }
}
const mutations = {  // mutations:用commit来触发mutations中的方法,从而触发数据更新
    changeName(state,res){  
        state.baseInfo.name = res.name
    },
    changeAge(state,res){
        state.baseInfo.age += res.value
    },
    ALERTNAME(state,res){
        state.baseInfo.name += res.name
    }
}
// const commit = {}
const getters = {   // 通过state状态派生出其他依赖项
    otherage:function(state){
        return state.baseInfo.age + 1
    },
    moreinfo:function(state,getter){  // 接收其他getter参与这个getter的运算
        return '姓名:'+ state.baseInfo.age + '年龄:'+ getter.otherage + 1
    },
    whileage:(state)=> function(id){
        return state.baseInfo.age + id
    },
}
const actions = {
    alertName(context,res){   // Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,通常会将context解构出来
        // 所以我们可以直接用context.getters,context.state;但ontext 对象不是 store 实例本身。
        context.commit('ALERTNAME',res)  // res要传给mutation函数
    },
    alertName2({commit},res){
        setTimeout(()=>{
            commit('changeAge',res)
        },2000)
        
        setTimeout(()=>{
            commit('ALERTNAME',res)
        },1000)
    },

    // 使用Promise组合action
    actionA({commit},res){
        return new Promise((resolve,reject)=>{
            if(res.value){
                commit('changeAge',res)
                resolve()
            }else{
                console.log('无传参!!!')
                reject()
            }
            
        })
    },
    actionB({dispatch,commit},res){
        return dispatch('actionA',res).then(()=>{
            commit('ALERTNAME',res)
        })
    },
    // 使用async/await 组合action
    async actionC({commit}){        
        commit('ALERTNAME',await getRes()) //getRes先执行 利用getRes得到res
    },
    async actionD({dispatch,commit},res){    
        await dispatch('actionA',res) // 等待 actionA 完成
        // await dispatch('actionA',res).then(()=>{
        //     console.log('actionA执行了')
        // })
        commit('ALERTNAME',await getRes()) // 利用getRes得到res
    }
}
const store = new Vuex.Store({
    state,
    mutations,
    getters,
    actions
})  
export default store  // 导出store状态,方便的main.js中引入,

总结Action

1.派发action :

this.$store.dispatch('alertName2',{
        name:'--action2',
        value:5
      })
2. 使用mapActions:
...mapActions([
      'alertName',
      'alertName2'
    ]),
3.使用Promise异步操作来组合Action
3.使用async/await异步操作来组合Action
 
 
 
 
 
posted @ 2021-08-29 11:00  程序员瑶琴  阅读(236)  评论(0编辑  收藏  举报