Search code examples
vue.jsvuexnuxt.js

Clone / Copy state is returning empty state


I am having an issue using lodash's cloneDeep to clone the user object passed in from the store. When I attempt to render the data in the template {{ user }} shows the data retrieved from the store and {{ userCopy }} shows the empty store. I am not sure why this is happening, I am new to Vue.

store/staff.js

import StaffService from '~/services/StaffService.js'
export const state = () => ({
  user: {
    offers: '',
    legal: ''
  }
})
export const mutations = {
  SET_USER(state, user) {
    state.user = user
  },
}

export const actions = {

  fetchUser({ commit, getters }, id) {
    const user = getters.getUserById(id)

    if (user) {
      commit('SET_USER', user)
    } else {
      StaffService.getUser(id)
        .then((response) => {
          commit('SET_USER', response.data)
        })
        .catch((error) => {
          console.log('There was an error:', error.response)
        })
    }
  },

}

export const getters = {
  getUserById: (state) => (id) => {
    return state.staff.find((user) => user.id === id)
  }
}

pages/settings/_id.vue

<template>
  <div>
    {{ user }} // will display the whole object 
    {{ userCopy }} // will only display empty store object
  </div>
</template>

<script>
import _ from 'lodash'

data() {
  return {
    userCopy: _.cloneDeep(this.$store.state.staff.user)
  }
},
computed: {
  ...mapState({ user: (state) => state.staff.user })
},
created() {
   this.$store.dispatch('staff/fetchUser', this.$route.params.id)
},
</script>

Solution

  • My guess would be that a Vue instance's data is initialized before state becomes available. While computed props are populated/updated as their data source change.

    If the component doesn't need to change the value of user during runtime, I'd suggest turning it into a computed property.

    If your component does change the value during runtime (such as when it's v-model'd to an input), there are two approaches you can do.

    Method 1: Using mounted hook

    This is done by placing user in data property and then assigning a value when the instance is mounted, like so:

    mounted () {
      this.$data.userCopy = _.cloneDeep(this.$store.state.staff.user)
    }
    

    Method 2: Using computed with getter and setter functions.

    Normally, you shouldn't change a computed value. But it can be done using a setter function. With this, when Vue detects an attempt to change a computed prop it will execute set() with the old and new values as arguments. This function would change the value at its source, allowing get()'s returned value to reflect this. For example:

    computed: {
      userCopy: {
        get () {
          return _.cloneDeep(this.$store.state.staff.user)
        },
        set (newValue) {
          this.$store.commit('updateStaff', newValue) // Replace this line with your equivalent state mutator.
        }
      }
    }