Setting up parameters and arguments in Vuex mutations: A guide

I am currently developing a todo list application using Vue.js, Vuex, and Firebase. The functionality of the app seems to be in working order with the Store file effectively managing the retrieval and display of entered todo items to and from Firestore. However, I have encountered a query regarding the configuration of parameters in Vuex. The REMOVE_TODO function within mutations (refer to store.js) seems to expect two arguments, even though only the "id" argument is utilized in the actual function's code. Removing the initial argument (in this case, "state") triggers an error message in the console stating: "Function CollectionReference.doc() requires its first argument to be of type non-empty string, but it was: a custom Object object". My question pertains to why the REMOVE_TODO function necessitates two arguments to function correctly when only the "id" parameter is utilized in the function. Why is the presence of the additional argument essential? The relevant sections of my code are provided below for reference. Thank you!

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
    }
  }
})

Answer №1

It's important to understand that when working with JavaScript function invocation, arguments are passed by position rather than name - a concept not specific to Vuex.

In your code snippet, you have REMOVE_TODO: (state, id) => {, but the names state and id are only relevant within the function itself. From the caller's perspective, these names could be anything, as what matters is their respective positions. It can just as easily be written as REMOVE_TODO: (a, b) => {.

When Vuex invokes the mutation, it will pass the state object as the first argument and the payload as the second argument, effectively calling:

mutations.REMOVE_TODO(state, payload)

It's crucial to note that the argument names do not hold significance outside of the function. While you could define the function as REMOVE_TODO: (id) => {, it won't change the fact that the first argument passed by the caller will still be the state object, regardless of how it's named inside the function.

The positioning of arguments in function definitions plays a key role. Dropping an argument from the end does not affect other arguments' positions, making optional arguments placement towards the end a common practice among API designers.

In mutations, the state is always necessary because mutations are intended to modify the state. If you find yourself performing asynchronous tasks within mutations, they should be moved to actions instead, as mutations need to remain synchronous.

Avoid using this within a Vuex store; all necessary data should be accessed through function arguments. Any manipulation of the state should be directed through state. For example, state.errors = error rather than this.errors = error.

Update:

Here's the requested code snippet:

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)
  })
}

Note that this implementation does not address potential race conditions.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Having trouble executing 'vue ui' in npm with nodejs vue/cli

Trying to set up Vue tool chain on a fresh Win10pro system has been quite challenging, as I kept encountering various errors that seem to stem from the same source. Upon running vue ui, the following error message pops up: @vue/cli 4.5.15 PS C:\U ...

The SvelteKit server successfully loaded data, displaying it on the sources/index page in the Chrome

I am currently in the process of developing a basic web application that utilizes self-hosted Pocketbase on the backend and SvelteKit as a meta framework. Recently, I discovered that the data loaded by my server is visible in the browser's sources/in ...

a single line within a compartment

I am encountering an issue with the code snippet below, which is responsible for generating the location of different records within a table: return ( <TableRow> <TableCell > // some code_1 < ...

Create an mp3 file using the arrayBuffer functionality

Struggling with StackOverflow, I attempted to record audio from a Raspberry Pi using Node.js (1). The audio stream is then sent through a WebSocket server (code omitted for simplicity), where a Vue.js WebSocket listens to the stream. My goal is to save thi ...

Changing the color gradient of a range column chart in ApexCharts

Currently, I am working on a project where I am trying to incorporate a waterfall chart using ApexCharts. Unfortunately, the Waterfall chart is not readily available with ApexCharts, so I am experimenting with modifying the range column chart into a Waterf ...

Enhance the functionality of selectize.js by incorporating select options through ajax

I'm currently working on implementing options to a select box using AJAX and selectize.js. When not using selectize.js, everything functions correctly. The two select boxes are interconnected so that when one is updated, the values in the other select ...

Issues encountered during the installation of Electron JS

Having trouble installing electronjs in Node.js 18 LTS and NPM 10? Getting an error message like this? PS C:\Users\Administrator.GWNR71517\Desktop\electron> npm install electron --save-dev npm ERR! code 1 npm ERR! path C:\Users& ...

Guide on exporting data to PDF using Vuetify

I am looking to generate a PDF using Vuetify with image formatting. Here are the data points that I want to include in the PDF file: https://i.stack.imgur.com/gyh7x.png https://i.stack.imgur.com/tCUU8.png My challenge lies in creating tables, labels, an ...

Utilizing hyperlinks to dynamically remove elements from a webpage with the power of HTML5 and JavaScript

Looking for guidance on how to create a link that will remove two specific list items from an unordered list located above the link. As a beginner, any assistance is greatly appreciated! ...

JavaScript form callbacks in Rails 3 are failing to trigger

My Rails 3 callbacks are not triggering for some unknown reason. Here's the form code I'm using: <%= form_tag('/create', :method => "post", :remote => true ,:id => "create") do %> <% end %> And this is the javascr ...

Unable to assign an ID value to a <span> element within a <th v-for="" > tag

I am attempting to assign the ID value of the span tag within a for loop using v-for. <table class="APPPPTable" style="width:100%;font-size:11px;"> <thead> <tr> <th v-for="heading in tableInfo.columns" class="text-c ...

Selenium - How to pass a file path to a dynamically generated input element that is not visible in the DOM

Check out this example of HTML code: This is how you create a visible button and display the selected file: <button id="visible-btn">visible button</button> <p>selected file is: <span id="selected-file"></spa ...

Guide to sending a post request with parameters in nuxt.js

I am trying to fetch data using the fetch method in Nuxt/Axios to send a post request and retrieve specific category information: async fetch() { const res = await this.$axios.post( `https://example.com/art-admin/public/api/get_single_cat_data_an ...

What is the method to access a form using jQuery? How can I extract the percentage symbol "%" from the entered amount?

I am working on developing a fee calculator using jQuery. In order to achieve this, I need to access forms. Here is the code I have so far: <form id="fee"> <input type="text" title="fee" placeholder="Place the amount that you would like to se ...

Discover the best method for summing all values within a JSON object that contains multiple unique keys

What is the best way to sum up all values in a JSON object? The object provided below contains values that are in string format and it has different keys. var numbers = { x: "4", y: "6", z: "2" }; The result should be: total ...

jQuery is not defined when importing reactjs, bootstrap, and npm modules

Having trouble using Bootstrap in my React app, as I keep getting an error message saying Error: Bootstrap's JavaScript requires jQuery. I've already imported jQuery and tried various solutions found in other posts like: import $ from 'jque ...

Modifying CSS style according to the contents of an HTML element

Creating a room allocation page with multiple panel boxes using Bootstrap. Each box represents a bed - highlighted in red if occupied and green if vacant. Clicking on a green panel redirects to the room allocation page, while clicking on a red panel goes t ...

Combining the Powers of ExpressJS and MeteorJS

I am currently using an Epress JS rest api to send data to a MongoDB database. I'm curious if it's feasible to incorporate Meteor JS for fetching these values from the MongoDB. Any insights or suggestions would be greatly valued. Thank you ...

The assigned type does not match the type 'IntrinsicAttributes & { children?: ReactNode; }'. This property is not assignable

I have been struggling to resolve this issue, but unfortunately, I have not found a successful solution yet. The error message I am encountering is: Type '{ mailData: mailSendProps; }' is causing an issue as it is not compatible with type &apos ...