Vue.js:数据没有通过状态更改进行更新,因此重新渲染不会发生

时间:2018-03-19 01:35:00

标签: vue.js vuejs2 video.js

我有一个可重复使用的组件,它是一个video.js视频播放器。在初始DOM加载时传入数据时,此组件可正常工作。

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

父组件通过道具传递视频数据。我也有这个设置用于多个视频,它可以正常使用一个或多个。

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

我将初始状态设置为我的Vuex商店中所有用户的通用视频。

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

这是在videos 中的数据中设置的(稍后设置为getFreeVideo)

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

我在data()中将videos设置为在created()生命周期内的商店中的getFreeVideo:

    this.videos = this.getFreeVideo

..并检查用户是否拥有个人视频并更新created()生命周期中的状态。

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

这会使用axios发出请求并成功返回我们的视频数据。

我正在使用mapState import { mapState } from 'vuex来监视状态更改。

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

我没看到为什么this.videos没有更新。 在这里,我对预期行为的假设是videos[]从状态更改和组件的重新呈现更新。

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

vuex Vuex ..但是,videos[]永远不会更新,因此视频组件永远不会获得道具新道具等。

几点说明:

  • 已尝试使用v-if 隐藏子组件(并在状态更改后显示)
  • 尝试setTimeout进行测试,但数据将通过,然后videoJS播放器永远不会正确实例化(必须有初始数据)
  • 尝试使用本地方法/不使用Vuex状态
  • 控制台显示错误TypeError: Cannot read property '_withTask' of undefined,但即使演示视频正确加载也会发生这种情况,所以这似乎无关紧要,而且我在这里找不到任何任何未定义的内容。

TL; DR

我基本上无法在状态改变后让子组件重新渲染。 虽然我可以使用不同的结构将数据导入videos[],但它仍然不会重新渲染。

为什么数据无法通过,重新渲染永远不会发生?

请不要发布只包含“了解反应性”链接的答案或其他解释。

附加@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
}

3 个答案:

答案 0 :(得分:3)

根据您发布的代码,考虑模板:

videos

从中获取 data () { return { videos: freeVideo } }

freeVideo

虽然它是从videos初始化的,但在您的代码中没有任何地方显示 getFreeVideo 的更新。

<强>解决方案:

您已经在computed: { ...mapState(['getFreeVideo']) } 计算:

中映射了状态
<div v-for="video in getFreeVideo" :key="video.id">

使用它:

videos

更新

  

我将数据()中的 this.videos = this.getFreeVideo 设置为商店内的getFreeVideo   created()生命周期:

this.videos

这还不足以让this.getFreeVideo更新this.getFreeVideo。只要某些内容设置为this.getFreeVideo,它就会更改this.videos,而不是this.videos

如果您想在this.getFreeVideo更改时自动更新watch: { getFreeVideo() { this.videos = this.getFreeVideo } } ,请创建观察者:

videos

然后继续使用v-for中的<div v-for="video in videos" :key="video.id">

{{1}}

答案 1 :(得分:1)

如果未在模板代码中某处引用计算属性(例如“使用”)vue将跳过反应性。

首先,您构建商店和州属性的方式有点令人困惑。

我会:

1)在商店状态中有“视频”属性

2)将其初始化为空数组

3)在应用程序启动时,使用“加载”默认值正确填充它,并使用将“默认”视频推送到它的突变

4)以mapGetter

的名称为其组建videos组件

5)每当您加载一个“更新”可能视频的组件时,就会调度该动作并调用相应的变异来替换商店“视频”属性

注意:如果组件可以包含不同的“默认”视频,那么您可能希望在商店中将videos属性初始化为false。然后,这允许您拥有一个计算属性,该属性使用商店中videos属性的getter,如果它是false

我的意思是,对于第一种情况

// 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
    } 
  }

}

个人:给他们更好的名字-_-,第一个选项是最清晰的

答案 2 :(得分:0)

事实证明整个问题与video.js有关。我很想删除这个问题,但我不希望任何帮助失去任何积分的人。

此处的解决方案和输入确实有助于重新考虑我对观察者的使用或我是如何尝试这一点的。我现在最终只使用中央商店,因为它工作正常,但这需要稍后重构。

我不得不放弃使用video.js作为播放器,而普通的html5视频播放器可以毫无问题地工作。