Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mutation #8

Open
lazyken opened this issue Mar 14, 2018 · 0 comments
Open

Mutation #8

lazyken opened this issue Mar 14, 2018 · 0 comments

Comments

@lazyken
Copy link
Owner

lazyken commented Mar 14, 2018

基本用法

每个 mutation 包含一个字符串的事件类型 (type)和一个回调函数(handler)。这个回调函数接受 state 作为第一个参数:

count store = new Vuex.Store({
  state:{
    count:1  
  },
  mutations:{
    increment (state) {
      //变更状态
      state.count++
    }
  }
})

触发mutation,应该像下面这样提交mutation的type

store.commit('increment')

提交载荷(Payload)

我们可以向stroe.commit传入额外的参数,即mutation的载荷( payload )

//...
mutations:{
  increment(state,n){
    state.count += n
  }
}

store.commit('increment',10)

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

//...
mutations:{
  increment(state,payload){
    state.count += payload.amount
  }
}

store.commit('increment',{
  amount:10
})

对象风格的提交方式

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

store.commit({
  type:'increment',
  amount:10
})

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

mutations:{
  increment(state,payload){
    state.count += payload.amount
  }
}

Mutation 需遵守 Vue 的响应规则

1.最好提前在你的 store 中初始化好所有所需属性。
2.当需要在对象上添加新属性时,应该:

  • 使用 Vue.set(obj, 'newProp', 123), 或者

  • 以新对象替换老对象。例如,利用对象展开运算符我们可以这样写:

      state.obj = { ...state.obj, newProp: 123 }

Mutation 必须是同步函数

一条重要的原则就是要记住 mutation 必须是同步函数。为什么?请参考下面的例子:

mutations: {
  someMutation (state) {
    api.callAsyncMethod(() => {
      state.count++
    })
  }
}

现在想象,我们正在 debug 一个 app 并且观察 devtool 中的 mutation 日志。每一条 mutation 被记录,devtools 都需要捕捉到前一状态和后一状态的快照。然而,在上面的例子中 mutation 中的异步函数中的回调让这不可能完成:因为当 mutation 触发的时候,回调函数还没有被调用,devtools 不知道什么时候回调函数实际上被调用——实质上任何在回调函数中进行的状态的改变都是不可追踪的。

在组件中提交 Mutation

在组件中可以使用 this.$store.commit('xxx') 提交 mutation,或者使用 mapMutations 辅助函数将组件中的 methods 映射为 store.commit 调用(需要在根节点注入 store)。例子:

<div id="app">
  <my-count></my-count>
  <button @click="increment">+</button>
  <!-- 注意这里以对象形式提交参数 -->
  <button @click="incrementBy({amount:10})">amount+</button>
  <button @click="decrement">-</button>
  <button @click="add">add</button>
</div>
const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    incrementBy(state, payload) {
      state.count += payload.amount
    },
    increment(state) {
      state.count++
    },
    decrement(state) {
      state.count--
    }
  }
})
const Counter = {
  template: '<div>{{count}}</div>',
  computed: {
    count() {
      return this.$store.state.count
    }
  }
}
new Vue({
  el: '#app',
  store,
  components: {
    'my-count': Counter
  },
  methods: {
    ...Vuex.mapMutations([
      'increment',
      'incrementBy',
      'decrement'
    ]),
    ...Vuex.mapMutations({
      add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')`
    })
  }
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant