Search code examples
javascriptarraysvue.jsvuex

VueJS reactivity: Replace an array with data


I still have trouble why certain ways of changing data work, while others do not. I tried this example:

    watch: {
      '$store.state.linedata': function() {this.redraw()}
    },
    methods: {
      redraw() {
        this.chartOptions.series[0].data = this.$store.state.linedata
      }
    },
    data() {
      return {
        chartOptions: {
          chart: {
            type: this.type
          },
          series: [{
            data: this.$store.state.linedata,
            name: "Test Series",
            color: this.color
          }]
        }
      }
  }

This setup works, whenever I change the linedata in my store, the component gets updated. However, for me it would be more intuitive to update the data like this, without referencing this.chartOptions.series[0].data:

  redraw() {
    this.$store.state.linedata = [1,2,3,4,5,6]
  }

This will update the state correctly, but however not cause to update the component with the new data. Why does the second way not work and is my first way the correct way to do it? I feel like I am missunderstanding some core concept here.What would a best practice look like?

Thank you!


Solution

  • From the Vuex docs you can read:

    The only way to actually change state in a Vuex store is by committing a mutation

    It means that you should not try to do this.$store.state.linedata = [1,2,3,4,5,6]. It may throw an error depending on your Vuex settings in the console by the way. Instead, create a mutation like so:

    mutations: {
      updateLineDate(state, lineDate) {
        state.lineData = lineData;
      }
    }
    

    And then call:

    this.$store.commit("updateLineDate", [1, 2, 3, 4, 5, 6]);
    

    To automatically update your chart's data, I would suggest creating a computed property in your Vue component. To make it reactive to changes, map your attribute using mapState:

    import { mapState } from "vuex";
    
    // ...
    
    computed: {
      ...mapState("lineData"),
      chartData() {
        return {
          chart: {
            type: this.type
          },
          series: [{
            data: this.lineData,
            name: "Test Series",
            color: this.color
          }]
        }
      }
    }
    

    Then remember to provide chartData to your chart component instead of chartOptions in my example.