xagos
xagos

Reputation: 98

How to mutate VueJS prop?

Hi i'm having trouble understanding how to mutate a prop value in vue js. I'm using vue-chartjs to dynamically rerender a chart using chartjs. The behaviour works but I get a console message warning when I fire off the updateValues() function.

Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "myData"

How do I properly mutate the prop?

// Parent Component
<bar-graph :myData="dataCollection" :height="250"></bar-graph>

data () {
  return {
    dataCollection: {
      labels: [2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017],
      datasets: [
        {
          label: 'Sample Lables',
          backgroundColor: 'red',
          data: [5000, 5000, 5000, 5000, 5500, 5500, 10000, 5500, 5500]
        }
      ]
    }
  }
},
methods: {

  updateValues () {
    this.dataCollection = {
      labels: [5000, 5000, 5000, 5000, 5500, 5500, 10000, 5500, 5500],

      datasets: [
        {
          label: 'Sample Lables',
          backgroundColor: 'red',
          data: [5000, 5000, 5000, 5000, 5500, 5500, 10000, 5500, 5500]
        }
      ]
    }
  }
}
      
      
//Child component bar graph

import { Bar } from 'vue-chartjs'

export default Bar.extend({

  props: ['myData'],

  mounted () {
    this.renderChart(this.myData, {responsive: true, maintainAspectRatio: false})
  },
  watch: {
    myData: function () {
      console.log('destroy')
      this._chart.destroy()
      this.renderChart(this.myData, {responsive: true, maintainAspectRatio: false})
    }
  }
})

Upvotes: 3

Views: 2493

Answers (2)

Aemilianvs
Aemilianvs

Reputation: 1

A comment / addition to @TheCascadian's answer: If myData is an Object, then this.passedData would be a reference to the same object, so you'll still get that warning. You might consider using cloneDeep from lodash to have a real inner copy of the property and use it internally accordingly.

Upvotes: 0

TheCascadian
TheCascadian

Reputation: 505

There is no way to "properly" mutate a prop, because it is a input to a component.

I recommend importing the data passed via the prop to the component's state and then using accordingly. By using this local copy, you avoid mutating the prop and getting that warning.

export default Bar.extend({

  props: ['myData'],

  data() {
    return {
      passedData: null
    }
  }

  mounted() {
    // Import data from prop into component's state
    this.passedData == this.myData;
    // Use as desired
    this.renderChart(this.myData, {
      responsive: true,
      maintainAspectRatio: false
    })
  },
  watch: {
    myData: function() {
      console.log('destroy')
      this._chart.destroy()
      this.renderChart(this.myData, {
        responsive: true,
        maintainAspectRatio: false
      })
    }
  }
})

Upvotes: 2

Related Questions