Skip to content
On this page

vue2-状态管理(二)

上篇文章中说了 state 和 getters,本篇文章就来说说 mutations 和 actions。 提交 mutations 是改变 state 的唯一方式,不能用异步操作。actions 通过分发 action 来提交 mutation,可包含异步操作,比如 xhr 。

mutations

声明 mutations:

js
// mutations.js
import vue from 'vue'
export default {
  CHANGE_LAST_NAME(state, newLastName) {
    state.lastName = newLastName
  },
  CHANGE_AGE(state, params) {
    state.age = params.age + 5
  },
  // 新增一个属性
  SET_REPOS(state, repos) {
    // 给 state 新添加属性
    vue.set(state, 'repoList', repos)
  }
}

使用 mutations

  1. 通过 mapMutations 映射方法;
  2. 在方法中 调用 this.$store.commit('mutaion')
  3. 可以在 mutation 种给 state 新增状态(属性),新增的状态会响应到视图上。
html
<template>
  <div class="store">
    <p>基本信息:{{this.info}}</p>
    <input type="text" name="age" id="age" v-model="age" placeholder="请输入年纪" />
    <button @click="changeAge">修改年纪</button>
    <button @click="changeAge2">修改年纪2</button>
    <p>年纪:{{this.$store.state.age}}</p>
    <input type="text" v-model="lastName" placeholder="请输入姓氏" @input="changeLastName" />
  </div>
</template>
<script>
  import CustomInput from '_c/CustomInput.vue'
  import {
    mapState,
    mapGetters,
    mapMutations
  } from 'vuex'
  export default {
    name: 'Store',
    data() {
      return {
        age: '',
        lastName: ""
      }
    },
    methods: {
      handleInput(val) {
        this.value = val
      },
      //方法名和 muations 相同
      ...mapMutations(['CHANGE_LAST_NAME', 'CHANGE_AGE']),
      // 将 `this.changeAge2()` 映射为 `this.$store.commit('CHANGE_AGE')`
      ...mapMutations({
        changeAgeAlias: 'CHANGE_AGE'
      }),
      changeAge() {
        // 传递载荷
        // this.$store.commit('CHANGE_AGE', { age: Number.parseInt(this.age) })
        //对象提交方式
        // this.$store.commit({ type: 'CHANGE_AGE', age: Number.parseInt(this.age) })
        this.CHANGE_AGE({
          age: Number.parseInt(this.age)
        })
      },
      changeAge2() {
        this.changeAgeAlias({
          age: Number.parseInt(this.age)
        })
      },
      changeLastName() {
        // this.$store.commit('CHANGE_LAST_NAME', this.lastName)
        this.CHANGE_LAST_NAME(this.lastName)
      },
    }
  }
</script>

actions

mutation 只能是同步操作,为了使用异步操作,Vuex 提供了 actions。

  • Action 提交的是 mutation,而不是直接变更状态。
  • Action 可以包含任意异步操作。

声明 actions

  • action 接收一个和 store 具有相同属性和方法的对象,可 context.commit 提交 mutation;
  • 可以解构赋值,获取 commitdispatch,commit 用于提交 mutation, dispatch 用于分发其他 action。
js
import http from 'axios'
export default {
  // action 接收一个和 store 具有相同属性和方法的对象,可 context.commit 提交 mutation
  changeAgeAsync(context, params) {
    console.dir(context)
    //模拟异步操作
    setTimeout(() => {
      context.commit('CHANGE_AGE', params)
    }, 5000)
  },
  //通过 github API 获取我的 github 仓库信息
  async repos({
    commit,
    dispatch
  }, username) {
    let response = await http.get(`https://api.github.com/users/${username}/repos`)
    let repoList = response.data
    commit('SET_REPOS', repoList)
    // 分发其他 action 形成组合 action
    dispatch('changeAgeAsync', {
      age: 30
    })
    // 给 state 新添加属性 不能直接改变 state
    // vue.set(state,'repoList',repoList)
  }
}

在组件中使用 actions

  • 通过 mapActions 映射为方法。
  • this.$store.dispatch
html
<template>
  <div class="store">
    <input type="text" name="age" id="age" v-model="age" placeholder="请输入年纪" />
    <button @click="changeAge">修改年纪</button>
    <p>年纪:{{this.$store.state.age}}</p>
    <input type="text" v-model="lastName" placeholder="请输入姓氏" @input="changeLastName" />
    <hr>
    <button @click="getRepos">获取仓库列表</button>
    <h2>我的仓库列表:</h2>
    <ol>
      <li v-for="(item, index) in repoList" :key="index">{{item.full_name}}</li>
    </ol>
  </div>
</template>
<script>
  import {
    mapState,
    mapActions
  } from 'vuex'
  export default {
    name: 'Store',
    data() {
      return {
        age: '',
        lastName: ""
      }
    },
    methods: {
      ...mapActions(['changeAgeAsync', 'repos']),
      changeAge() {
        // this.$store.dispatch('changeAgeAsync',{ age: Number.parseInt(this.age) })
        this.changeAgeAsync({
          age: Number.parseInt(this.age)
        })
      },
      getRepos() {
        // this.$store.dispatch('repos','jackzhoumine')
        this.repos('jackzhoumine')
      }
    },
    computed: {
      //计算属性名和 state 属性名相同:传入数组
      ...mapState(['repoList'])
    }
  }
</script>

module

状态对象很复杂时用 module 划分。 这个似乎用得很少。需要用时看veux 文档即可。

总结

  1. 提交 mutation 是改变你 state 的唯一方式;
  2. 方法执行上:
    • dispatch 分发 action ;
    • commit 提交 mutation。
  3. 辅助方法的映射
  • getters、state 映射为计算属性;
  • actions、mutations 映射为法法。
  1. 分离功能:
  • state 保存数据;
  • getters 是对 state 的操作;
  • actions 要提交 mutation;
  • mutations 改变 state。
  1. 异步与同步:
  • action 封装异步处理;
  • mutation 只能是同步。
  1. 视图响应

( vue component dispatch → ) vue component commit state → ( getters →) vue component

  1. state 对象太过复杂,使用 module 划分。

参考

Released under the MIT License.