我有一个可重用的组件,它是一个 video.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>
我正在为我的 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: []
}
}
我将 videos
在 data() 中设置为在 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()
也包含新数据:
..但是,
videos[]
永远不会更新,因此视频组件永远不会获得道具新道具等。
几点注意事项:
- 已经尝试过,用
v-if
隐藏子组件 (并在状态更改后显示) - 尝试
setTimeout
进行测试,但数据会通过,然后 videoJS 播放器永远不会正确实例化 (必须有初始数据) - 尝试使用本地方法/不使用 Vuex 状态来执行此操作
- 控制台显示错误
TypeError: Cannot read property '_withTask' of undefined
但即使演示视频正确加载也会发生这种情况,因此这似乎无关紧要,我在这里找不到任何显示为未定义的东西。
TL;博士
状态更改后,我基本上无法让子组件重新渲染。虽然我可以使用不同的结构将数据放入 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
}
原文由 Jordan 发布,翻译遵循 CC BY-SA 4.0 许可协议
注意:在这个答案的底部,请参阅我对 Vue 的更新/反应性问题提出的一般观点。
现在,关于这个问题, _根据您发布的代码_,考虑模板:
它从以下位置选择
videos
:尽管它从
freeVideo
初始化,但在您的代码中没有任何地方显示videos
的更新。解决方案:
您已经在
getFreeVideo
中映射了状态:用它:
更新:
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.’);
} })
/* 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 }
person.nickname: {{ person.nickname }}
person.address: {{ person.address }}
For more info, read the comments in the code. Or check the docs on Reactivity (link below).
要掌握 Vue 的这一部分,请查看 Official Docs on Reactivity - Change Detection Caveats 。这是必须阅读的!