Am4nzi
Am4nzi

Reputation: 67

Vuex store update not applying re-render in component

I am using Vue.js with TypeScript.

Link to my repo: https://github.com/Am4nzi/ac-vue

I have a component called Albums.vue which is rendering an iFrame. I am attempting to update the source URL of the iFrame when a button is clicked in another component called AlbumsLeft.vue. This updates a property in my store state called albumURL.

The issue I am having is that the computed property I am using to set the URL in Albums.vue is not updating the URL in the iFrame element when the value in the store changes.

My understanding is that a computed property should automatically update when it detects a change, however I could be mistaken. If this is the wrong approach, could anyone recommend a better one?

I can confirm that the state in the store does change as expected when the button is clicked via inspecting Vuex in Vue devtools.

I am setting the iFrame source URL dynamically using v-bind:

<iframe
        :src="imageSrcURL"
...

I am getting the URL from the store and setting it to a variable called imageSrcUrl via a computed property:

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';

@Component
export default class Albums extends Vue {
  get getAlbumURL() {
    return this.$store.state.albumURL;
  }

  private imageSrcURL = this.getAlbumURL;
}
</script>

The event handler within AlbumsLeft.vue is called changeAlbum:

changeAlbum(name: string) {
    this.$store.dispatch(
      'updateAlbumURL',
      'https://bandcamp.com/EmbeddedPlayer/album=4251477660/size=large/bgcol=333333/linkcol=ffffff/tracklist=false/transparent=true',
    );
  }

This is my store:

export default new Vuex.Store({
  state: {
    currentAlbumId: '',
    albumURL: 'https://bandcamp.com/EmbeddedPlayer/album=3937120203/size=large/bgcol=333333/linkcol=ffffff/tracklist=false/transparent=true',
  },
  mutations: {
    setAlbumID(state, albumId) {
      state.currentAlbumId = albumId;
    },
    setAlbumUrl(state, albumURL) {
      state.albumURL = albumURL;
    },
  },
  actions: {
    updateAlbumID({ commit }, albumId) {
      commit('setAlbumID', albumId);
    },
    updateAlbumURL({ commit }, albumId) {
      commit('setAlbumUrl', albumId);
    },
  },
  modules: {
  },
});

Thanks in advance!

Upvotes: 1

Views: 1068

Answers (1)

tao
tao

Reputation: 90277

The problem is here:

get getAlbumURL() {
  return this.$store.state.albumURL;
}

private imageSrcURL = this.getAlbumURL;

getAlbumURL changes correctly, but you're not reassigning it to imageSrcURL, which remains unchanged, hence no update in the template.

Either use getAlbumURL in :src of <iframe> or, if you do need imageSrcURL for some functionality you haven't shown here, place a watch on getAlbumURL and update imageSrcURL each time the former changes.

Side note: imageSrcURL should not be private if you use it in <template>. private means it's only accessible to the class. The template is outside the class. Basically, your production build will fail because of this error.

If the only reason for having imageSrcURL is because you can't mutate getAlbumURL, you can actually, using a setter:

get getAlbumURL() {
  return this.$store.state.albumURL;
}
set getAlbumURL(val) {
  this.$store.dispatch('updateAlbumURL', val);
}

Now you can safely use getAlbumURL as v-model or whatever. And you might also understand why you should avoid naming properties getStuff. stuff will do.

Upvotes: 1

Related Questions