Avoid altering the Vuex store state directly without using mutation handlers in VueJS

I am currently working on developing a listenAuth function that monitors the "onAuthStateChanged" event in firebase to inform the vuex store whenever a user logs in or out. From what I can gather, I am only updating state.authData using the mutation handler. Am I overlooking something?

I encountered the following error:

[vuex] Do not modify the vuex store state directly outside of mutation handlers.

Below is the JavaScript code snippet from my App.vue file (component):

<script>
// import Navigation from './components/Navigation'
import * as actions from './vuex/actions'
import store from './vuex/store'
import firebase from 'firebase/app'

export default {
  store,
  ready: function () {
    this.listenAuth()
  },
  vuex: {
    actions,
    getters: {
      authData: state => state.authData,
      user: state => state.user
    }
  },
  components: {
    // Navigation
  },
  watch: {
    authData (val) {
      if (!val) {
        this.redirectLogin
        this.$route.router.go('/login')
      }
    }
  },
  methods: {
    listenAuth: function () {
      firebase.auth().onAuthStateChanged((authData) => {
        this.changeAuth(authData)
      })
    }
  }
}
</script>

This is my action function (changeAuth)

export const changeAuth = ({ dispatch, state }, authData) => {
  dispatch(types.AUTH_CHANGED, authData)
}

Here are the essential parts of my store:

const mutations = {
  AUTH_CHANGED (state, authData) {
    state.authData = authData
  }
}

const state = {
  authData: {}
}

Answer №1

Encountered a similar issue in my own store:

  state: {
    items: []
  },
  mutations: {
    SetItems (state, payload) {
      // Solution
      state.items = payload.items
    }
  },
  actions: {
    FetchItems ({commit, state}, payload) {
      api.getItemsData(payload.sheetID)
        .then(items => commit('SetItems', {items}))
    }
  }

To resolve it, I replaced state.items = payload.items with the following:

state.items = payload.items.slice()

The reasoning behind this is that arrays are stored as references in JavaScript and changes to payload.items could impact Vuex outside of its scope. Therefore, utilizing a fresh copy of payload.items is necessary.

For state objects, consider using:

state.someObj = Object.assign({}, payload.someObj)

Avoid using

JSON.parse(JSON.stringify(someObj))
due to its slower performance.

Answer №2

After encountering a challenging issue, I discovered that the problem only arose when attempting to save the auth/user data in the Vuex state.

Instead of...

const mutations = {
  AUTH_CHANGED (state, authData) {
    state.authData = authData
  }
}

...changing it to...

const mutations = {
  AUTH_CHANGED (state, authData) {
    state.authData = JSON.parse(JSON.stringify(authData))
  }
}

could potentially resolve your particular situation.

Answer №3

When facing the same problem, I found a solution by utilizing lodash for data cloning.

state.someStatehere = $lodash.cloneDeep(data)

Answer №4

After analyzing various responses, it seems that the main cause is the object stored in the state being altered by a reference to it. Many have suggested creating a duplicate of the object.

Another approach is to clear the state while the object is undergoing modification. This method proves useful when duplicating the object is not feasible for some reason. For instance:

bla({ state } {}) {
  mutatingMethod(state.xxx);
},

If you are aware that mutatingMethod is changing xxx, consider implementing the following solution:

bla({ state } {}) {
  let xxx = state.xxx
  commit("SET_XXX", null)
  mutatingMethod(xxx);
  commit("SET_XXX", xxx)
},

Answer №5

If you're having trouble with this issue, here is an alternative solution that worked for me:

auth()
  .onAuthStateChanged((user) => {
    if (user) {
      updateUserInfo(MUTATION_TYPES.SET_USER, { ...user.toJSON() });
    }
  })

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

Personalizing structural directives in Vue

Angular allows for the use of structural directives to manage how elements are displayed. Is it possible to define similar structural instructions in Vue? ...

Struggling to execute an AJAX request in JavaScript

I am a beginner in .Net development and I am trying to make a call to the client's server. When I test the code using POSTMAN, it works fine. However, when I use the same code/headers in JavaScript, I do not get the desired result. Here is the code I ...

Issue with child rows not functioning properly in DataTables when utilizing Datetime-moment

I've successfully integrated this data into live.datatables.net and almost have it running smoothly. However, I am encountering an issue with displaying the last detail as a child element. The final part of the row should be shown with the label "Mes ...

Content in the <core-animation-pages> element is extending beyond the borders of the main DIV when the "slide-from-right" effect is applied (Polymer

Check out this quick video I made to demonstrate the issue: I have successfully incorporated core-animation-pages into my web application. I have three different divs that transition using the slide-from-right animation without any problems. However, in d ...

Issue with Mongoose Promise failing to transfer data to the following chain

When querying MongoDB using mongoose with promises, I encounter an issue where the result is only accessible in the initial .then(function(results){ // can send the result from here..}). However, when I manipulate the results and attempt to pass them to th ...

Omit child DIV element in JavaScript and the Document Object Model

I have a situation with two div elements. One is <div class="card" id="openWebsite"> and the other is a sub-division <div class="card__btn"> Here's the issue: When someone clicks on the main div, they get red ...

Animate an image to the right when clicked, then return it to the left with a second click

Seeking help with animating a set of images to move individually 300px right on first click, and then 300px left when clicked again. I'm currently facing an issue where my code is not working. It could be due to A) syntax errors or B) the images not ...

Having trouble with ng-click in my AngularJS Restful application

I was attempting to create CRUD operations in AngularJS. Unfortunately, I am facing an issue where my ng-click is not functioning properly. Below is the code for my list.html: <div class="container"> <input type="text" ng-controlle ...

Invoke a Python function from JavaScript

As I ask this question, I acknowledge that it may have been asked many times before. If I missed the answers due to my ignorance, I apologize. I have a hosting plan that restricts me from installing Django, which provided a convenient way to set up a REST ...

Check the Full Calendar to see if any events are scheduled for today

I have a group of users who need to save their availability. Currently, I am utilizing Full Calendar and looking for a way to prevent them from adding the same event multiple times on a single day. My tech stack includes VueJs and all events are stored in ...

Is your Phonegap and Jquery app experiencing delays in script loading?

I recently developed a phonegap + JQM application and encountered an issue with the loading time of external JavaScript files. To elaborate, when the app starts, the initial file that appears is loader.html. In this file, I have included several JS files ...

Awaiting a response from the http.get() function

Currently, I am in the process of creating a login feature using Angular and Ionic 2. This feature aims to verify if the user is registered in the database through a PHP server and return a user ID. However, I have encountered an issue with the asynchronou ...

Reveal unseen information on the webpage upon clicking a link

I have successfully implemented a fixed header and footer on my webpage. The goal is to make it so that when a user clicks on a link in either the header or footer, the content of that page should appear dynamically. While I have explored various styles, ...

How can you utilize a bind function to deactivate a button?

Can someone help me figure out how to temporarily disable a button using the bind function for 10 seconds? jQuery('#wsf-1-field-155').bind('click', function() { ScanRegistration(); setTimeout(function() { jQuery('#wsf- ...

The next function is not defined error in the controller function

Everything was running smoothly until I suddenly encountered this error message: ReferenceError: next is not defined. I'm puzzled because I didn't make any changes to this function. const Users = require('../data/users.model') exports ...

A comparison between the if statement and switch statement in JavaScript

Let's dive into a challenging scenario for those who consider themselves experts in JavaScript, particularly with switch and if statements. Here is how it typically works: var a = 1; if (a == 1) alert("true"); This is just a basic example. Now, let& ...

No files located by the server

My experience with writing a basic express script to serve a webpage with embedded Javascript has been quite frustrating. The server seems to struggle finding the files I provide, and what's even more aggravating is that it sometimes works but then su ...

jQuery Form: Despite the Ajax response being visible on the page, it does not appear in the source code

Utilizing Jquery Form for an Ajax image upload. This is the relevant HTML code: <div class="input_con imageupload_con"> <form action="processupload.php" method="post" enctype="multipart/form-data" id="MyUploadForm"> < ...

Error Encountered with Nested Angular Material Tabs

Is there a way to prevent changes made to the upper tab in md-align-tabs attribute from affecting the inner tab when one tab is nested inside another using md-tabs? If so, how can I achieve this? <md-content layout="column" layout-fill> <md-ta ...

Unable to trigger Vuejs click event when using v-if condition

I've encountered a strange issue. I'm attempting to trigger a method when an element is clicked in a v-for loop, but it doesn't seem to work when using v-if or v-show. Here's a sample of my HTML code: <div class="chosen-drop custom ...