Vuex之state、mapState、...mapState、getters、mapGetters、...mapGetters

我在项目中发现如下代码:

computed: {
  ...mapGetters([
    'permission_routes',
    'sidebar'
  ]),
  activeMenu() {
    const route = this.$route
    const { meta, path } = route
    if (meta.activeMenu) {
      return meta.activeMenu
    }
    return path
  },
}

其中,...mapGetters是什么语法呢?我查询资料进行了解,它是Vuex的语法。

然后我了解到Vuex的几个概念,state,mapState和...mapState。

一、State

vuex的state和vue的data有很多相似之处,都是用于存储一些数据或者说状态值。这些值将实现被挂载数据和dom的双向绑定,也就是当你改变值的时候可以触发dom的更新。

state在使用的时候一般被挂载到子组件的computed计算属性上,这样有利于state的值发生改变的时候及时响应给子组件。

let state = {
  count: 1,
  name: 'lyh',
  sex: '男',
  from: 'china'
}
export default state
<template>
  <div id="example">
    <button @click="decrement">-</button>
    {{count}}
    {{dataCount}}
    <button @click="increment">+</button>
  </div>
</template>
<script>
export default {
  data () {
    return {
      dataCount: this.$store.state.count //用data接收
    }
  },
  computed:{
    count(){
      return this.$store.state.count //用computed接收
    }
  }
  methods: {
    increment () {
      this.$store.commit('increment')
    },
    decrement () {
      this.$store.commit('decrement')
    }
  }
}
</script>

结果为用data接收的值不能及时响应更新,用computed就可以。

 

二、mapState

mapState是state的语法糖。

在使用mapState之前,要导入这个辅助函数。

import { mapState } from 'vuex'

使用方式为

<template>
  <div id="example">
    <button @click="decrement">-</button>
    {{count}}
    {{dataCount}}
    <button @click="increment">+</button>
    <div>{{sex}}</div>
    <div>{{from}}</div>
    <div>{{myCmpted}}</div>
  </div>
</template>
<script>
import { mapState } from 'vuex'
export default {
  data () {
    return {
      str: '国籍',
      dataCount: this.$store.state.count
    }
  },
  computed: mapState({
    count: 'count', // 第一种写法
    sex: (state) => state.sex, // 第二种写法
    from: function (state) { // 用普通函数this指向vue实例,要注意
      return this.str + ':' + state.from
    },
    // 注意下面的写法看起来和上面相同,事实上箭头函数的this指针并没有指向vue实例,因此不要滥用箭头函数
    // from: (state) => this.str + ':' + state.from
    myCmpted: function () {
      // 这里不需要state,测试一下computed的原有用法
      return '测试' + this.str
    }
  }),
  methods: {
    increment () {
      this.$store.commit('increment')
    },
    decrement () {
      this.$store.commit('decrement')
    }
  },
  created () {
    // 写个定时器,发现computed依旧保持了只要内部有相关属性发生改变(不管是当前实例data中的改变,还是vuex中的值改变)都会触发dom和值更新
    setTimeout(() => {
      this.str = '国家'
    }, 1000)
  }
}
</script>

在使用的时候,computed接收mapState函数的返回值,你可以用三种方式去接收store中的值,具体可以看注释。

事实上第二种和第三种是同一种,只是前者用了ES6的偷懒语法——箭头函数,在偷懒的时候要注意一个问题,this指针的指向问题。

我们不要在vue中为了偷懒使用箭头函数,会导致很多很难察觉的错误,如果你在用到state的同时还需要借助当前vue实例的this,请务必使用常规写法。

当然computed不会因为引入mapState辅助函数而失去原有的功能——用于扩展当前vue的data,只是写法会有一些奇怪。

如果你已经写了一大堆的computed计算属性,做了一半发现你要引入vuex,还想使用mapState辅助函数的方便,你可以做下列事情。

//之前的computed
computed:{
    fn1(){ return ...},
    fn2(){ return ...},
    fn3(){ return ...}
    ........
}
//引入mapState辅助函数之后
 
computed:mapState({
    //先复制粘贴
    fn1(){ return ...},
    fn2(){ return ...},
    fn3(){ return ...}
    ......
    //再维护vuex
    count:'count'
    .......
})

我们希望我们可以不用去做一些复制粘贴的无用操作,而是直接使用mapState,希望它能自动融入到当前生产环境中。

ES6+(或者说ES7)提供了这个方便。

 

三、...mapState

事实上...mapState并不是mapState的扩展,而是...对象展开符的扩展。

这样,我们就可以自由的使用mapState了。

//之前的computed
computed:{
    fn1(){ return ...},
    fn2(){ return ...},
    fn3(){ return ...}
    ........
}
//引入mapState辅助函数之后
 
computed:{
    //原来的继续保留
    fn1(){ return ...},
    fn2(){ return ...},
    fn3(){ return ...}
    ......
    //再维护vuex
    ...mapState({  //这里的...不是省略号了,是对象扩展符
        count:'count'
    })
}

学习了state,mapState和...mapState之后,我们可以继续学习getters,mapGetters,...mapGetters这几个概念。

 

四、getters

Vuex提供了state这样的状态统一管理树,你可以在vue中用computed计算属性接收这些公共状态以便使用,当然你也可以在接收原值的基础上对这个值做出一些改造,如

computed:{
  sex:function(){
      return this.$store.state.sex + '加个字符串,算是改造'    
  }
}

但是如果你的其他组件也要使用这种改造方式去改造这个值,那你可能不得不去复制粘贴这个函数到别的组件中。

当然为了解决这个问题,vuex本身就提供了类似于计算属性的方式,getters可以让你从store的state中派生出一些新的状态。

当然如果不是多个组件要用到这个状态,或者说每个子组件用到的派生属性不一样,那么你完全可以不用getters。

//state.js
let state = {
  from: 'china',
  arr: [2, 3, 1, 4, 6]
}
export default state
// getters.js
// 第一个参数是state
let address = (state) => {
  return '国籍:' + state.from
}
// 第二个参数可以访问getters
let addressMore = (state, getters) => {
  return '其他描述' + getters.address
}
// return 一个function,这个function可以传参,当然这个function最后会返回一个具体的数值
//本例中这个方法用于查询state中的arr数组是否存在某个值
let findArr = (state) => (number) => {
  let ifExit = state.arr.find((n) => n === number) // arr.find是ES6语法中数组的扩展
  if (typeof (ifExit) === 'undefined') {
    return false
  } else {
    return true
  }
}
export {address, addressMore, findArr}
<template>
  <div>
    <div>{{from}}</div>
    <div>{{from2}}</div>
  </div>
</template>
 
<script>
// import { mapGetters } from 'vuex'
export default {
  computed: {
    from: function () {
      return this.$store.getters.address
    },
    from2: function () {
      return this.$store.getters.addressMore
    }
  },
  created () {
    console.log(this.$store.getters.findArr(2))
    console.log(this.$store.getters.findArr(7))
  }
}
</script>

结果为:

 

五、mapGetters辅助函数

与mapState类似,可辅助理解。

<template>
  <div>
    <div>{{from}}</div>
    <div>{{from2}}</div>
  </div>
</template>
 
<script>
import { mapGetters } from 'vuex'
export default {
  computed:  mapGetters({
      'from': 'address',
      'from2': 'addressMore',
      'find': 'findArr'
  }),
  created () {
    console.log(this.find(1)) // 由于getters已经通过computed挂载到当前实例,所以你不需要再通过this.$store.getters的方法去访问
    console.log(this.$store.getters.findArr(2))
    console.log(this.$store.getters.findArr(7))
  }
}
</script>

 

六、...mapGetters

<template>
  <div>
    <div>{{from}}</div>
    <div>{{from2}}</div>
  </div>
</template>
 
<script>
import { mapGetters } from 'vuex'
export default {
  computed:  {
    ...mapGetters({
      'from': 'address',
      'from2': 'addressMore',
      'find': 'findArr'
    })
  },
  created () {
    console.log(this.find(1)) // 由于getters已经通过computed挂载到当前实例,所以你不需要再通过this.$store.getters的方法去访问
    console.log(this.$store.getters.findArr(2))
    console.log(this.$store.getters.findArr(7))
  }
}
</script>

很多情况下是用不到getters的,请按需使用,不要用getters去管理state的所有派生状态,如果有多个子组件或者说子页面要用到,才考虑用getters。

 

posted @ 2021-05-07 14:46  罗毅豪  阅读(619)  评论(0编辑  收藏  举报