在 Vuex 中更新对象的属性时,Getter 没有反应

Gec*_*o29 6 vue.js vuex vuetify.js

我在我的应用程序中遇到了一些有关反应性的问题。

我有一个 Vuex 商店,其中有一个对象“歌曲”,其中包含“歌曲”对​​象,其中键是它们的 ID。对于其中的每个歌曲对象,我都有各种属性,有问题的属性是“播放”一个布尔值。

例如

songs = {
   2: {playing: false},
   7: {playing: true)
}
Run Code Online (Sandbox Code Playgroud)

在我的应用程序中,我有一个列表,对所有这些歌曲使用 v-for,并通过一个按钮切换歌曲的播放属性。当按下按钮时,我会发送我创建的动作,传入与按下的按钮相关联的歌曲 ID

this.$store.dispatch('toggleSongPlaying', {songid: songid})
Run Code Online (Sandbox Code Playgroud)

根据歌曲是否正在播放,我希望显示适当的图标。

我的问题的简化 vuex 商店包括以下内容:

const state = {
  songs: {}
};

const mutations = {
  update_song_playing(state, payload) {
     var songObj = state.songs[payload.songid]
     var playingBool = !songObj.playing
     Vue.set(songObj, 'playing', playingBool)
  }
};

const actions = {
  toggleSongPlaying({ commit }, payload) {
     commit("update_song_playing", payload)
  }
};

const getters = {
  getSongs: state => state.songs
};
Run Code Online (Sandbox Code Playgroud)

设置功能工作正常,问题在于反应性。按下切换按钮时,不会发生图标更改。然而,触发重新渲染会导致图标发生变化。在我的组件中,我像这样使用 mapGetters:

computed: {
    ...mapGetters({
      songs: "getSongs"
    })
}
Run Code Online (Sandbox Code Playgroud)

为了使反应性与此嵌套对象正常工作,我是否缺少某些东西?

感谢您的任何建议!

编辑 - 列表和图标的模板代码

<v-list dense>
   <v-subheader>Songs List</v-subheader>
   <v-list-item-group v-model="activeSong" color="primary">
         <v-list-item
              v-for="(song, songID) in songs"
              :key="songID"
         >
               <v-icon class="mr-3" @click.stop="toggleSongPlaying(songID)">{{song.playing ? 'mdi-pause' : 'mdi-play'}}</v-icon>

                // song details etc...
                <v-list-item-content>
                    <v-list-item-title>
                    </v-list-item-title>
                </v-list-item-content>
                    
          </v-list-item>
   </v-list-item-group>
</v-list>
Run Code Online (Sandbox Code Playgroud)
methods: {
   toggleSongPlaying(songid) {
       this.$store.dispatch('toggleSongPlaying', {songid: songid})
   }
},
Run Code Online (Sandbox Code Playgroud)

EDIT2 在创建的单独组件中,我用这样的歌曲填充歌曲对象

created() {
    var songid = "12"
    var song = {
        length: ...,
        playing: false,
    }

    var payload = {
        song: song,
        songid: songid
    }

    this.$store.dispatch('addSong', payload)
},
Run Code Online (Sandbox Code Playgroud)

在 Vuex 中

行动:

addSong({ commit }, payload) {
   commit("add_song", payload);
}
Run Code Online (Sandbox Code Playgroud)

突变体:

add_song(state, payload) {
    state.songs[payload.songid] = payload.song
},
Run Code Online (Sandbox Code Playgroud)

Phi*_*hil 7

您将歌曲分配到您的状态的方式不是被动的

对于对象

Vue 无法检测属性添加或删除

更改您的add_song突变以用songs新的(包括新歌曲)替换state 属性。这被视为songs不可变的

add_song: (state, { songid, song }) => {
  state.songs = {
    ...state.songs,
    [ songid ]: { ...song } // break any object references, thank me later
  }
},
Run Code Online (Sandbox Code Playgroud)

现在您不需要使用,Vue.set因为该payload属性已被被动添加。你update_song_playing可以简单地

update_song_playing: (state, { songid }) => {
  const song = state.songs[songid];
  if (song) {
    song.playing = !song.playing;
  }
}
Run Code Online (Sandbox Code Playgroud)

您也可以Vue.set在您的add_song突变中使用,但我一直觉得基于 Flux 的存储最适合使用不可变数据