如何在Vuex突变中设置参数和参数

时间:2019-06-28 15:33:47

标签: javascript firebase vue.js google-cloud-firestore vuex

我正在使用Vue.js,Vuex和Firebase构建待办事项列表应用程序。该应用程序似乎可以正常运行,因为“商店”文件成功管理了输入的待办事项(与Firestore之间的关联)的检索和渲染。但是,我仍然对在Vuex中设置参数有疑问。变异中的REMOVE_TODO函数(请参阅store.js)似乎需要两个参数,即使“ id”是该函数实际代码中唯一引用的参数。换句话说,如果我删除了初始参数(在这种情况下为“ state”),则控制台将返回一个错误消息:“ Function CollectionReference.doc()要求其第一个参数的类型为非空字符串,但是它是:一个自定义对象对象”。我的问题是:如果“ id”参数是该函数中实际使用的唯一参数,为什么这个REMOVE_TODO函数需要有两个参数才能正常运行?为什么需要其他论点?这是下面的代码。谢谢!

app.vue

<template>
  <div id="app" class="container">
    <input class="form-control" :value="newTodo" @change="getTodo" placeholder="I need to...">
    <button class="btn btn-primary" @click="addTodo">Add New Post</button>
    <ul class="list-group">
        <li class="list-group-item" v-for="todo in this.$store.getters.getTodos" :key="todo.id">
            {{todo.title}}
            <div class="btn-group">
                <button type="button" @click="remove(todo.id)" class="btn btn-default btn-sm">
                <span class="glyphicon glyphicon-remove-circle"></span> Remove
                </button>
            </div>
        </li>
    </ul>
  </div>
</template>
<script>
export default {
  beforeCreate: function() {
    this.$store.dispatch('setTodo')
  },
  methods: {
    getTodo(event) {
      this.$store.dispatch('getTodo', event.target.value)
    },
    addTodo() {
      this.$store.dispatch('addTodo')
      this.$store.dispatch('clearTodo')
    },
    remove(id){
      this.$store.dispatch('removeTodo', id)
    }
  },
  computed: {
    newTodo() {
      return this.$store.getters.newTodo
    },
    todos(){
      return this.$store.getters.todos
    }
  }
}
</script>
<style>
body {
  font-family: Helvetica, sans-serif;
}
li {
  margin: 10px;
}
</style>

store.js

import Vue from 'vue'
import Vuex from 'vuex'
import db from '../firebase'

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    todos: [],
    newTodo: '',
    errors: ''
  },
  mutations: { //syncronous, committed
    GET_TODO: (state, todo) => {
      state.newTodo = todo
    },
    ADD_TODO: state => {
      db.collection('items').add({
        title: state.newTodo,
        created_at: Date.now(),
      }).then(function(){
        console.log('Document successfully added')
      })
      .catch((error) => {
        this.errors = error
      })
    },
    REMOVE_TODO: (state, id) => {
       if (id) {
         db.collection("items").doc(id).delete().then(function() {
           console.log('Document successfully deleted')
         })
         .catch((error) => {
           this.errors = error
         })
       } else {
         this.errors = 'Invalid ID'
       }
    },
    CLEAR_TODO: state => {
      state.newTodo = ''
    },
    SET_TODO: state => {
      let todos = []
      db.collection('items').orderBy('created_at').onSnapshot((snapshot) => {
        todos = []
        snapshot.forEach((doc) => {
          todos.push({ id: doc.id, title: doc.data().title })
        })
        state.todos = todos
      })
    }
  },
  actions: { //asyncronous, dispatched
    getTodo: (context, todo) => {
      context.commit('GET_TODO', todo)
    },
    addTodo: context => {
      context.commit('ADD_TODO')
    },
    removeTodo: (context, id) => {
      context.commit('REMOVE_TODO', id)
    },
    clearTodo: context => {
      context.commit('CLEAR_TODO')
    },
    setTodo: context => {
      context.commit('SET_TODO')
    }
  },
  getters: {
    newTodo: state => state.newTodo,
    getTodos: state => {
      return state.todos
    }
  }
})

1 个答案:

答案 0 :(得分:1)

这与Vuex无关,这只是JavaScript函数调用的工作方式。参数是按位置而不是名称传递的。

您有REMOVE_TODO: (state, id) => {,但名称stateid仅在函数内有意义。在函数之外,从调用者的角度来看,这些名称无关紧要。就像REMOVE_TODO: (a, b) => {一样容易。

Vuex调用变异时,它将传递state对象作为第一个参数,而传递payload作为第二个参数。实际上是在打电话:

mutations.REMOVE_TODO(state, payload)

我重申,参数的名称实际上并不重要,只是它们的位置。

这是Vuex内部的内容,不是您直接控制的内容。如果您自己调用该函数,则可以传递任何所需的信息,但不是(也不应该)。相反,您(很正确)在呼叫commit。您将所需的payload传递给commit,然后Vuex将执行其余操作,调用相关的变异并将其传递给statepayload

将函数定义为REMOVE_TODO: (id) => {不会更改调用方传递的参数。第一个参数仍然是state对象。您已将其命名为id,但这没什么区别,它仍然是state对象。

通常,尝试删除第一个参数的问题是所有其他参数都有效地改组了,因此所需参数名称的位置不再与传递的参数位置匹配。从尾部删除一个参数没有其他问题,因为其他参数不会移动位置。因此,如果您只需要state而不是payload,则可以直接删除第二个参数。 API设计人员总是尝试将可选参数放在最后,以便可以删除它们而不会引起任何问题。

对于突变,payload很容易是不必要的,但始终需要state。突变的全部目的是更改state。如果您不更改state,则不应该使用突变。

如代码中所述,actions是异步的,而mutations需要是同步的。但这不是您所拥有的。当前,您的变体中有许多对Firebase的异步调用。所有这些都需要移到actions中。请注意,Promise始终是异步的,因此,如果您发现自己在突变内调用then,则说明这样做是错误的。唯一应该在mutations内部的部分是在修改state时。

您还需要避免在Vuex商店中使用this。您应该发现可以通过传递给函数的参数来访问所需的所有内容。当前,您的突变中有this.errors = error个和类似的突变。我假设应该是state.errors = error

更新

根据评论的要求:

SET_TODO (state, todos) {
  state.todos = todos
}
setTodo ({commit}) {
  db.collection('items').orderBy('created_at').onSnapshot(snapshot => {
    const todos = []

    snapshot.forEach(doc => {
      todos.push({ id: doc.id, title: doc.data().title })
    })

    commit('SET_TODO', todos)
  })
}

请注意,这不会尝试应对可能的比赛条件。