0

I'm importing an array called CHART_CARDS in a Vue component. This is meant to provide the initial state for another array, called chartCards, which a user can change.

import { CHART_CARDS } from '~/constants/chartCards'

...

export default {
  data(){
    return {
      chartCards: []
    }
  },
  async created(){
    if (this.$auth.user.settings && this.$auth.user.settings.length) {
      this.chartCards = this.$auth.user.settings
    } else {
      this.chartCards = CHART_CARDS
    }
  }
}

So the data property chartCards is either taken from the imported variable or from a pre-existing database table.

Here's where things get weird: I have a method called reset, which is supposed to restore the chartCards variable to the value of the imported array:

     async reset () {
         console.log('going to reset.  CHART_CARDS looks like:')
         console.log(CHART_CARDS)
         this.chartCards = CHART_CARDS
         await this.updateCards()
         console.log('chart cards after updating:')
         console.log(this.chartCards)
     }

Somehow, CHART_CARDS is also changed when chartCards is updated. The two console logs above print the same array, so the reset doesn't work. CHART_CARDS is changed nowhere else in the code; all references to CHART_CARDS are shown in the above code. How is its value being updated?

David J.
  • 1,753
  • 13
  • 47
  • 96
  • 1
    since `this.chartCards = CHART_CARDS` they're the same reference. so any change will be reflected in both vars. – Markus Dresch Oct 05 '20 at 13:24
  • @MarkusDresch . what could I do to fix this? I tried this.chartCards = Array.from(CHART_CARDS) , and it doesn't make a difference – David J. Oct 05 '20 at 13:29
  • 1
    i suspect you are modifying the objects inside the array. Array.from creates a shallow copy, resulting in a new array containing the same objects. if you indeed need a deep copy, one quick and dirty solution is to serialize/deserialize it with JSON.stringify/JSON.parse. – Markus Dresch Oct 05 '20 at 13:34
  • 1
    see https://stackoverflow.com/questions/122102/what-is-the-most-efficient-way-to-deep-clone-an-object-in-javascript/5344074#5344074 – Markus Dresch Oct 05 '20 at 13:35

1 Answers1

1

As others have mentioned in the comments, your CHART_CARDS array probably contains objects, and you are most likely changing these objects somewhere in your code.

There is an easy way around this with some minor API tweaks.

~/constants/chartCards.js

export function getChartCards () {
  return [
    {...},
    {...},
    ...
  ]
}

App.vue

import { getChartCards } from '~/constants/chartCards'

...

export default {
  data(){
    return {
      chartCards: []
    }
  },
  async created(){
    if (this.$auth.user.settings && this.$auth.user.settings.length) {
      this.chartCards = this.$auth.user.settings
    } else {
      this.chartCards = getChartCards()
    }
  }
}

Since we're always creating a new array with different objects, changes made to one chartCards instance will not reflect in another.

If you absolutely want to stick with your current API, then that can potentially be achieved as well. You just need to create a deep-copy of your CHART_CARDS object before assigning it.

import { CHART_CARDS } from '~/constants/chartCards'

...

export default {
  data(){
    return {
      chartCards: []
    }
  },
  async created(){
    if (this.$auth.user.settings && this.$auth.user.settings.length) {
      this.chartCards = this.$auth.user.settings
    } else {
      this.chartCards = JSON.parse(JSON.stringify(CHART_CARDS)) // This will not work if your CHART_CARDS has methods
    }
  }
}
Guru Prasad
  • 4,053
  • 2
  • 25
  • 43
  • thanks, clear answer. Is there any reason to prefer one approach above the other? – David J. Oct 05 '20 at 14:19
  • 1
    Ideally, as much as possible you want to avoid usage of `JSON.parse(JSON.stringify(...))`. For larger objects, it might be expensive to do so. In that regard, the first option is preferred. Additionally, the first option also gives you the flexibility of having methods in your `CHART_CARDS` object. – Guru Prasad Oct 05 '20 at 14:22