我有一个可重用的视频组件.js视频播放器.当数据在初始DOM加载时传入时,该组件工作正常.

我需要弄清楚为什么我的组件在Vuex中更新状态后没有重新渲染.

父组件通过props 传递视频数据.我也有这套可以用于多个视频,它可以很好地用于一个或多个视频.

<div v-for="video in videos" :key="video.id">
  <video-player :videoName="video.videoName" :videoURL="video.videoURL" :thumbnail="video.thumbnail"></video-player>
</div>

我正在为Vuexstore 中的所有用户将初始状态设置为通用视频.

getFreeVideo: [
  {
    videoName: "the_video_name",
    videoURL:  "https://demo-video-url.mp4",
    thumbnail: "https://s3.amazonaws.com/../demo-video-poster.jpg"
  }
]

这是在videos (and later set to getFreeVideo)中的数据中设置的

 data () {
   return {
     videos: []
   }
 }

在创建的()生命周期内,我将data()中的videos设为getFreeVideo:

    this.videos = this.getFreeVideo

..判断用户是否有个人视频,并更新created()生命周期中的状态.

 this.$store.dispatch('getFreeVideo', 'the_video_name')

这会向axios发出请求,并成功返回我们的视频数据.

我用mapState import { mapState } from 'vuex来观察状态的变化.

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

我不明白为什么this.videos没有被更新.

如下所示,状态已更新,计算(computed)属性中的videoUpdate()也有新数据:

vuex

几点注意:

  • 已经try 过了,用v-if (and showing after state change)隐藏子组件
  • try 了setTimeout次测试,但数据会通过,然后videoJS播放器永远无法正确实例化(must have initial data)
  • try 使用本地方法执行此操作/未使用Vuex状态
  • 控制台显示错误TypeError: Cannot read property '_withTask' of undefined,但即使演示视频加载正确,这种情况也会发生,所以这似乎不相关,我在这里找不到任何显示为未定义的内容.

TL;DR

我基本上无法让子组件在状态更改后重新渲染.

Why is the data not making it through, and the re-render never happening?

Please don't post answers that only contain links to 'understanding reactivity' or something without any explanation.?

appended for @acdcjunior

//action   
getFreeVideo: (context, videoName) => {
    axios({
      method: 'post',
      url: 'https://hidden-for-posting',
      data: {
        action: 'getVideo',
        userId: '1777', // (hardcoded to test)
        videoName: videoName
      },
      headers: {
        'x-api-key': apiKey,
        'Content-Type': 'application/json'
      }
    })
    .then(response => {
      let video = [
        {
          videoName: response.data.videoName,
          videoURL: response.data.videoURLs.mp4,
          thumbnail: response.data.thumbnails['1280']
        }
      ]
      return context.commit('updateGetFreeVideo', video)
    })
    .catch(error => {
      if (error.response) {
        console.log(error.response)
      } else if (error.request) {
        console.log(error.request)
      } else {
        console.log('Error', error.message)
      }
      console.log(error.config)
    })
}

// mutation:
updateGetFreeVideo: (state, payload) => {
  return state.getFreeVideo = payload
}

// getter:
getFreeVideo: state => {
  return state.getFreeVideo
}

推荐答案

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


现在,关于问题based on the code you posted,考虑到模板:

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

它从以下方面挑选videos名:

 data () {
   return {
     videos: freeVideo
   }
 }

虽然它从freeVideo开始初始化,但在代码中没有显示update of 101.

Solution:

您已经将状态映射到getFreeVideo计算:

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

使用它:

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

Update:

我在data()中设置了videos,以在

    this.videos = this.getFreeVideo

这还不足以让this.videosthis.getFreeVideo保持同步.当某个值设置为this.getFreeVideo时,它只会改变this.getFreeVideo,而不是this.videos.

如果希望在this.getFreeVideo发生变化时自动更新this.videos,请创建一个观察者:

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

然后在v-for中继续使用videos:

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



Vue's reactivity

如果您的状态没有在视图中得到更新,则可能您没有在最佳状态下探索Vue:

要让Vue automatically对值更改做出react ,对象必须是initially declared in 100.或者,如果不是,他们必须是added using 101岁.

请参阅下面演示中的注释.或者打开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>

要掌握Vue的这一部分,请查看Official Docs on Reactivity - Change Detection Caveats.这是一本必读的书!

Vue.js相关问答推荐

设置Vite Vue 3需要多个应用程序输出目录

我可以手动访问 vue-router 解析器吗?

为什么在 Vue2 中调用 this.$emit() 后 props 没有立即更新?

如何将模板传递给EJS菜单

将初始值设置为可直接在 HTML 中使用的 vue.js 模型

Vuejs 和 Laravel 发布请求 CORS

VueJS:在组件之间使用全局对象的最佳实践?

使用数组元素的计算(computed)属性

有条件地在 Vue 中添加一个 CSS 类

VueJs this.method 不是函数?如何在 Vuejs 的另一个方法中调用一个方法?

确保在渲染组件之前加载 Vuex 状态

如何在异步功能上使用 debounce?

包含 Vue.js v-if 和 v-for 指令的 HTML 标签在加载时flash

ECMA6 中 nameFunction() {} 和 nameFunction () => {} 的区别

错误:Node Sass 尚不支持您当前的环境:Linux 64-bit with Unsupported runtime (88)

Vue CLI 3 sass-resources-loader - Options.loaders 未定义

更改时(change)调用函数

Vuetify RTL 风格

在 Vuejs 中放置 firebase.auth().onAuthStateChanged() 的位置

使用 vuex-persistedstate 仅使一个模块持久化