Vue.js: Data is not updating with state change so the re-render does not happen

If the computed property isn't referenced (e.g. "used") somewhere in your template code vue will skip reactivity for it.

First it's a bit confusing the way you're structuring the store and the state properties.

I would:

1) Have a "videos" property in the store state

2) Initialise it as an empty array

3) On application start populate it correctly with the "load" defaults, with a mutation that pushes the "default" video to it

4) Have the components mapGetter to it under the name of videos

5) Whenever you load a component that "updates" the possible videos, then dispatch the action and call the appropriate mutation to substitute the store "videos" property

Note: If components can have different "default" videos, then probably you'll want to have a videos property in the store that is initialised as false. This then allows you to have a computed property that uses the getter for the videos property in the store and in case it is false

What I mean is, for the first case

// store
state: {
  videos: []
}

getters: {
  videos(state) { return state.videos } 
}

//components

...
computed: {
  videos() {
    this.$store.getters.videos
  }
}

For the second case


// store
state: {
  videos: false
}

getters: { personal_videos(state) { return state.videos } }

//components
data() { return { default: default_videos } },
computed: {
  ...mapGetters([ 'personal_videos' ]),
  videos() {
    if (this.personal_videos) {
      return this.personal_videos
    } else {
      return this.default
    } 
  }

}

Personal: give them better names -_- and the first option is the clearest


So turns out the whole issue was with video.js. I'm half tempted to delete this question, but I would not want anyone who helped to lose any points.

The solution and input here did help to rethink my use of watchers or how I was attempting this. I ended up just using the central store for now since it works fine, but this will need to be refactored later.

I had to just forego using video.js as a player for now, and a regular html5 video player works without issues.


NOTE: at the bottom of this answer, see the general point I make about update/reactivity issues with Vue.


Now, about the question, based on the code you posted, considering the template:

<div v-for="video in videos" :key="video.id">

It picks the videos from:

 data () {
   return {
     videos: freeVideo
   }
 }

Although it initializes from freeVideo, in nowhere in your code you show an update of videos.

Solution:

You already have the state mapped in the getFreeVideo computed:

computed: {
  ...mapState(['getFreeVideo'])
}

Use it:

<div v-for="video in getFreeVideo" :key="video.id">

Update:

I'm setting videos in data() to getFreeVideo in the store within the created() lifecycle:

    this.videos = this.getFreeVideo

This is not enough to keep this.videos updated with whatever this.getFreeVideo is. Whenever something is set to this.getFreeVideo it will only change this.getFreeVideo, not this.videos.

If you want to automatically update this.videos whenever this.getFreeVideo changes, create a watcher:

watch: {
  getFreeVideo() {
    this.videos = this.getFreeVideo
  }
}

And then keep using videos in the v-for:

<div v-for="video in videos" :key="video.id">


Vue's reactivity

If your state is not getting updated in the view, perhaps you are not exploring Vue at its best:

To have Vue automatically react to value changes, the objects must be initially declared in data. Or, if not, they must be added using Vue.set().

See the comments in the demo below. Or open the same demo in a JSFiddle here.

new Vue({
  el: '#app',
  data: {
    person: {
      name: 'Edson'
    }
  },
  methods: {
    changeName() {
      // because name is declared in data, whenever it
      // changes, Vue automatically updates
      this.person.name = 'Arantes';
    },
    changeNickname() {
      // because nickname is NOT declared in data, when it
      // changes, Vue will NOT automatically update
      this.person.nickname = 'Pele';
      // although if anything else updates, this change will be seen
    },
    changeNicknameProperly() {
      // when some property is NOT INITIALLY declared in data, the correct way
      // to add it is using Vue.set or this.$set
      Vue.set(this.person, 'address', '123th avenue.');
      
      // subsequent changes can be done directly now and it will auto update
      this.person.address = '345th avenue.';
    }
  }
})
/* CSS just for the demo, it is not necessary at all! */
span:nth-of-type(1),button:nth-of-type(1) { color: blue; }
span:nth-of-type(2),button:nth-of-type(2) { color: red; }
span:nth-of-type(3),button:nth-of-type(3) { color: green; }
span { font-family: monospace }
<script src="https://unpkg.com/vue"></script>

<div id="app">
  <span>person.name: {{ person.name }}</span><br>
  <span>person.nickname: {{ person.nickname }}</span><br>
  <span>person.address: {{ person.address }}</span><br>
  <br>
  <button @click="changeName">this.person.name = 'Arantes'; (will auto update because `name` was in `data`)</button><br>
  <button @click="changeNickname">this.person.nickname = 'Pele'; (will NOT auto update because `nickname` was not in `data`)</button><br>
  <button @click="changeNicknameProperly">Vue.set(this.person, 'address', '99th st.'); (WILL auto update even though `address` was not in `data`)</button>
  <br>
  <br>
  For more info, read the comments in the code. Or check the docs on <b>Reactivity</b> (link below).
</div>

To master this part of Vue, check the Official Docs on Reactivity - Change Detection Caveats. It is a must read!