vuex使用

99 阅读3分钟

附:「这是我参与2022首次更文挑战的第5天,活动详情查看:2022首次更文挑战

前言

使用vuex的好处

1. 统一管理状态的好处

  • 能够在 vuex 中集中管理共享的数据,易于开发和后期维护
  • 能够高效地实现组件之间的数据共享,提高开发效率
  • 存储在vuex中的数据都是响应式的,能够实时保持数据与页面的同步

2. 什么样的数据适合存储在 vuex 中?

  • 一般情况下,只有组件之间共享的数据,才有必要存储到vuex中,对于组件中的私有数据,依旧存储在组件自身的data中即可

核心概念

State

state是唯一的公共数据源,所有共享的数据都要统一放到 Store 的 State 中进行存储

(1)存一个名字为 count 的公共变量

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    count:0
  },
  // ... 省略其他选项
})

(2)组件中访问该变量

第一种方式

this.$store.state.全局数据名称

示例:

<div>当前最新的count值为:{{this.$store.state.count}}</div>

第二种方式

  1. 在组件中按需导入 vuex 中的 mapState 函数
import {mapState} from "vuex"
  1. 将全局数据,映射为当前组件的计算属性(相当于把公共变量引用到我们自己组件中的计算属性,我们可以像使用计算属性一样使用它)
computed:{
 ...mapState(['count])
}

示例:

<template>
  <div>
    <div>当前最新的count值为:{{count}}</div>
    <button>-1</button>
  </div>
</template>

<script lang="js">
import {mapState} from 'vuex' // 1. 导入

export default {
  name: "Sub",
  computed:{
    ...mapState(['count'])  // 2. 将全局属性映射到computed,做为我们自己的一个计算属性
  }
}
</script>

Mutation

Mutation 用于变更 Store 中的数据

  • 在vuex中,只能通过 mutation 变更 store 数据,不可以直接操作 store 中的数据【见本mutation例子尾示例】
  • 通过这种方式虽然操作起来稍微繁琐一些,但是可以集中监控所有的数据变化

(1)mutations中定义函数

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    count:0
  },
  mutations: {
    add(state){
      state.count++
    }
  },
})

(2)第一种方式:组件中使用 mutations 中的 add 函数

  • 用commit来触发mutations中的函数
<template>
  <div>
    <h3>当前最新的count值为:{{this.$store.state.count}}</h3>
    <button @click="add1"> +1 </button>
  </div>
</template>

<script lang="js">
export default {
  name: "addition",
  methods:{
    add1(){
      this.$store.commit('add');
    }
  }
}
</script>

输出结果:

(3)mutations 可以传递参数

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    count:0
  },
  mutations: {
    add(state){
      state.count++
    },
    // 接收参数
    addN(state,step){
      state.count += step
    }
  },
})

(4)组件中使用

<template>
  <div>
    <h3>当前最新的count值为:{{this.$store.state.count}}</h3>
    <button @click="add1"> +1 </button>
  </div>
</template>

<script lang="js">
export default {
  name: "addition",
  methods:{
    add1(){
      this.$store.commit('add');
    },
    add2(){
      this.$store.commit('addN',10);
    }
  }
}
</script>

输出结果:

(5)第二种使用方式

<template>
  <div>
    <h3>当前最新的count值为:{{count}}</h3>
    <button @click="sub1"> -1 </button>
    <button @click="sub2"> -N </button>
  </div>
</template>

<script lang="js">
import {mapState,mapMutations} from 'vuex'
export default {
  name: "subtraction",
  computed:{
    ...mapState(['count'])
  },
  methods:{
    ...mapMutations(['sub','subN']),
    sub1(){
      this.sub()
    },
    sub2(){
      this.subN(10)
    }
  }
}
</script>

输出结果:

(5)假设现在要实现一个功能,点击按钮1秒后加1,此时你应该想到直接在mutations函数中加定时器,但是我们要知道定时器是异步的方法,mutation是不允许异步代码的存在,下面来看下 mutations存在异步代码会怎么样?


看到了么,视图变了,但是原本的值没有改变!所以如果有异步方法代码,要注意不能在 mutation 里使用,而是使用 Action

补充:不合法的写法

  • 不允许直接修改 state里的数据
  • 只能通过 mutation 触发来修改

小结

  • 在vuex中只有mutation才有权力修改state里面的数据
  • mutation里面只能写同步的代码

Action

  • Action用于处理异步任务
  • 如果通过异步操作变更数据,必须通过Action,而不能使用Mutation,但是再 Action中还是要通过触发 Mutation的方式接变更的数据

(1)在 actions 中定义函数

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    count:0
  },
  mutations: {
    add(state){
      state.count++
    },
    addN(state,step){
      state.count += step
    },
    sub(state){
      state.count--
    },
    subN(state,step){
      state.count -= step
    }
  },
  actions: {
    addAsync(context){
        setTimeout(()=>{
           context.commit('add')
        },1000)
    }
  },
})

组件中使用 actions 中的函数

  • dispatch方法的作用就是触发Action中的某一个函数
<template>
  <div>
    <h3>当前最新的count值为:{{this.$store.state.count}}</h3>
    <button @click="add3">1s后+1</button>
  </div>
</template>

<script lang="js">
export default {
  name: "addition",
  methods:{
    add3(){
      this.$store.dispatch('addAsync')
    },
  }
}
</script>

输出结果:1秒后加1

(2)触发 acitons 时携带参数

 actions: {
    addNAsync(context,step){
      setTimeout(()=>{
        context.commit('addN',step)
      },1000)
    },
  },

组件中使用

<template>
  <div>
    <h3>当前最新的count值为:{{this.$store.state.count}}</h3>
    <button @click="add4">1s+N</button>
  </div>
</template>

<script lang="js">
export default {
  name: "addition",
  methods:{
    add4(){
      this.$store.dispatch('addNAsync',20)
    }
  }
}
</script>

输出结果:

(3)第二种触发 actions 方式

<template>
  <div>
    <h3>当前最新的count值为:{{count}}</h3>
    <button @click="sub3">1s后-1</button>
    <button @click="sub4">1s后-N</button>
  </div>
</template>

<script lang="js">
import {mapActions} from 'vuex'
export default {
  name: "subtraction",
  methods:{
    ...mapActions(['subAsync','subNAsync']),
    sub3(){
      this.subAsync()
    },
    sub4(){
      this.subNAsync(100)
    }
  }
}
</script>

输出结果:

Getter

  • Getter 用于对 Store 中的数据进行加工处理形成新的数据
  • Getter不会修改state里的值,只是一个包装作用,相当于计算属性

(1)定义 Getter

 getters: {
    showNum: state=>{
      return '当前最新的数量是['+ state.count +']'
    }
  }

组件中使用第一种方式

<h3>{{$store.getters.showNum}}</h3>

输出结果:

组件中使用第二种方式

<template>
  <div>
    <h3>{{showNum}}</h3>
  </div>
</template>

<script lang="js">
import {mapGetters} from 'vuex'
export default {
  name: "subtraction",
  computed:{
    ...mapGetters(['showNum']),
  },
}
</script>

输出结果:

简写方法

  • 针对 import 导入的方式,可以直接当计算属性给事件使用,减少了一个函数
<template>
  <div>
    <h3>{{showNum}}</h3>
    <button @click="sub"> -1 </button>
    <button @click="subN(10)"> -N </button>
    <button @click="subAsync">1s后-1</button>
    <button @click="subNAsync(100)">1s后-N</button>
  </div>
</template>

<script lang="js">
import {mapState,mapMutations,mapActions,mapGetters} from 'vuex'
export default {
  name: "subtraction",
  computed:{
    ...mapState(['count']),
    ...mapGetters(['showNum']),
  },
  methods:{
    ...mapMutations(['sub','subN']),
    ...mapActions(['subAsync','subNAsync']),
  }
}
</script>

输出结果:效果都还是一样的

总结

(1)

  • state存储全局变量数据
  • mutation相当于方法(同步代码的)
  • action处理异步代码
  • getter类似于计算属性,对state变量进行一层包装

(2)其他注意事项:

  • 在 actions 中,不能直接修改 state 中的数据,必须通过 context.commit() 触发某个 mutation 才行
  • 组件中可以直接获取vuex中state的变量,但是只限于展示这个值(官方建议使用 Getters 包装一下再展示),如果要在组件中直接对这个值进行修改会有问题(视图变了,但是值没有变)。state的变量只能是vuex中 mutation 和 action 来进行处理