更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。
为神马说是修改store中你的状态的唯一办法呢为何之前能修改呢

何为严格模式

在严格模式下,无论何时发生了状态变更且不是由 mutation 函数引起的,将会抛出错误。这能保证所有的状态变更都能被调试工具跟踪到。
说白就是在严格模式下,只能有mutation 函数修改state中的状态,要吗state里自己修改状态,不能从视口那里修改state中的状态
如下图
image.png

如何开启严格模式

  1. const store = new Vuex.Store({
  2. // ...
  3. strict: true
  4. })

发布环境需要关闭严格模式

发布环境就是生产环境。严格模式就是规范我们在开发模式的行为规范的
不要在发布环境下启用严格模式!严格模式会深度监测状态树来检测不合规的状态变更——请确保在发布环境下关闭严格模式,以避免性能损失。
类似于插件,我们可以让构建工具来处理这种情况:

  1. const store = new Vuex.Store({
  2. // ...
  3. strict: process.env.NODE_ENV !== 'production'
  4. })

示例//在视口中修改state的状态的报错信息

image.png

使用Mutation

官方的对Mutation的简介

image.png

如何声明

更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。

  1. const store = new Vuex.Store({
  2. state: {
  3. count: 1
  4. },
  5. mutations: {
  6. increment (state) {
  7. // 变更状态
  8. state.count++
  9. }
  10. }
  11. })

如何调用

  1. this.$store.commit('increment');

如何使用辅助函数

除了在组件中使用 this.$store.commit(‘xxx’) 提交 mutation之外,还可以使用 mapMutations 辅助函数:

  1. import { mapMutations } from 'vuex'
  2. export default {
  3. // ...
  4. methods: {
  5. ...mapMutations([
  6. 'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')`
  7. ]),
  8. ...mapMutations({
  9. add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')`
  10. })
  11. }
  12. }

提交载荷(Payload)// 传递参数

你可以向store.commit传入额外的参数,即mutation的载荷(payload):

  1. mutations: {
  2. increment (state, n) {
  3. state.count += n
  4. }
  5. }
  1. store.commit('increment', 10)

在大多数情况下,载荷应该是一个对象,这样可以包含多个字段并且记录的mutation会更易读:

  1. mutations: {
  2. increment (state, payload) {
  3. state.count += payload.amount
  4. }
  5. }
  1. store.commit('increment', {
  2. amount: 10
  3. })

对象风格的提交方式

提交 mutation 的另一种方式是直接使用包含 type 属性的对象:

  1. store.commit({
  2. type: 'increment',
  3. amount: 10
  4. })

当使用对象风格的提交方式,整个对象都作为载荷传给 mutation 函数,因此 handler 保持不变:

  1. mutations: {
  2. increment (state, payload) {
  3. state.count += payload.amount
  4. }
  5. }

使用常量代替Mutation事件类型(type)

把这些常量放在单独的文件中可以让你的代码合作者对整个 app 包含的 mutation 一目了然:

  1. // mutation-types.js
  2. export const COUNT_INCREMENT = 'COUNT_INCREMENT'
  1. // store.js
  2. import Vuex from 'vuex'
  3. import { COUNT_INCREMENT } from './mutation-types'
  4. const store = new Vuex.Store({
  5. state: { ... },
  6. mutations: {
  7. [COUNT_INCREMENT] (state) {
  8. // ...
  9. }
  10. }
  11. })

视口中如何调用

  1. this.$store.commit('COUNT_INCREMENT',{
  2. num:10
  3. })

第二种方式

  1. import {COUNT_INCREMENT} from '@/components/store/mutation-types'
  2. this.$store.commit(COUNT_INCREMENT,{
  3. num:10
  4. })

Mutation 需遵守 Vue 的响应规则

既然 Vuex 的 store 中的状态是响应式的,那么当我们变更状态时,监视状态的 Vue 组件也会自动更新。这也意味着 Vuex 中的 mutation 也需要与使用 Vue 一样遵守一些注意事项:

  • 最好提前在你的 store 中初始化好所有所需属性。
  • 当需要在对象上添加新属性时,你应该
    • 使用 Vue.set(obj, 'newProp', 123) , 或者
    • 以新对象替换老对象。例如,利用对象展开运算符我们可以这样写:
      1. state.obj = { ...state.obj, newProp: 123 }
      vue 中对象添加新属性时是不会触发响应式的只用,只用通过Vue.set()和以新对象替换老对象

      示例

      ```javascript import Vue from ‘vue’ import Vuex from ‘vuex’ import { COUNT_INCREMENT, COUNT_OBJ, COUNT_MSG} from ‘./mutation-types’

Vue.use(Vuex)

export default new Vuex.Store({ // 启用严格模式,当在生产环境时取消严格模式 strict: process.env.NODE_ENV !== ‘production’, // 储存信息的仓库 state:{ obj:{a:1}, }, /**

  1. * 严格模式下,仓库可以修改状态值,但是视口不可以直接修改仓库的状态值,可以通过mutations修改仓库的状态值
  2. */
  3. mutations:{
  4. [COUNT_OBJ](state){
  5. // 不会触发响应式
  6. // state.obj.b = 3
  7. // 触发响应式
  8. Vue.set(state.obj, 'b' , '3')
  9. },
  10. }

})

  1. ```vue
  2. <template>
  3. <div class="home">首页
  4. <button @click="handleClick">click</button>
  5. <div>{{ obj }}</div>
  6. </div>
  7. </template>
  8. <script>
  9. import {mapGetters, mapState, mapMutations } from 'vuex'
  10. import {COUNT_INCREMENT} from '@/components/store/mutation-types'
  11. export default {
  12. data(){
  13. return {
  14. }
  15. },
  16. computed:{
  17. // 当触发单击事件时只会改变组件内count值
  18. ...mapState(['obj']),
  19. },
  20. methods:{
  21. handleClick(){
  22. this.$store.commit('COUNT_OBJ')
  23. console.log(this.obj)
  24. console.log(this.$store.state.obj)
  25. }
  26. },
  27. created(){
  28. }
  29. }
  30. </script>

表单处理

在Vuex的state上使用v-model时,由于会直接更改state的值,所以Vue会抛出错误。
如果想要使用双向数据的功能,就需要自己模拟一个v-model: :value=”msg” @input=”updateMsg”。

双向数据绑定

上面的做法,比v-model本身繁琐很多,所以我们还可以使用计算属性的setter来实现双向绑定:

  1. <input v-model="msg">
  1. computed: {
  2. msg: {
  3. get () {
  4. return this.$store.state.obj.msg;
  5. },
  6. set (value) {
  7. this.$store.commit(UPDATE_MSG, { value });
  8. }
  9. }
  10. }

Mutation 必须是同步函数

要记住 mutation 必须是同步函数。why?

  1. mutations: {
  2. [COUNT_INCREMENT] (state) {
  3. setTimeout(() => {
  4. state.count ++;
  5. }, 1000)
  6. },
  7. }

执行上端代码,我们会发现更改state的操作是在回调函数中执行的,这样会让我们的代码在devtools中变的不好调试:当 mutation 触发的时候,回调函数还没有被调用,devtools 不知道什么时候回调函数实际上被调用,任何在回调函数中进行的状态的改变都是不可追踪的。