Vue.js与Nuxt.js页面加载后向组件传递数据无法正常渲染的问题咨询
这个问题我之前开发Vue项目时也碰到过,核心原因是异步数据加载和组件生命周期的时机不匹配,具体来说:
父组件的mounted钩子中是异步调用getUsersSettings获取数据,但子组件的mounted钩子会比父组件异步请求完成的时间更早执行——因为初始时currentSection === 'Public account'为true,子组件会立刻挂载。这时候父组件的personalSettings还是空对象,子组件把这个空对象赋值给了personalInfo。
等父组件异步请求完成、personalSettings更新后,子组件的props虽然会变化,但data里的personalInfo是初始化时赋值的,不会自动跟着props更新。只有当你切换标签页时,子组件被v-if销毁后重新挂载,此时mounted再次执行,personalSettings已经有了完整数据,personalInfo才能拿到正确值,视图也就正常显示了。
修复方案(三种可选,推荐第一种)
方案1:监听props变化,同步更新personalInfo
在子组件中添加watch监听personalSettings的变化,当父组件数据更新时,自动同步到子组件的personalInfo中。如果是复杂对象,记得做深拷贝避免引用问题:
// 子组件的script部分 props: { personalSettings: { type: Object, default: () => {} } }, data() { return { personalInfo: {}, loading: false, showPopup: false } }, watch: { personalSettings: { handler(newVal) { // 深拷贝避免直接修改父组件数据 this.personalInfo = JSON.parse(JSON.stringify(newVal)); }, immediate: true, // 初始化时立即执行一次,确保首次加载就同步数据 deep: true // 如果对象有嵌套属性,开启深度监听 } }, // 可以去掉原来的mounted赋值了,watch的immediate已经处理了初始化逻辑 // mounted() { // this.personalInfo = this.personalSettings // }
方案2:用computed实现双向绑定(适合需要修改数据的场景)
如果需要在子组件中修改数据并同步回父组件,可以用带get/set的computed代替data,避免维护副本:
// 子组件的script部分 props: { personalSettings: { type: Object, default: () => {} } }, computed: { personalInfo: { get() { return this.personalSettings; }, set(newVal) { // 通过$emit通知父组件更新数据 this.$emit('update:personalSettings', newVal); } } }
然后父组件中使用.sync修饰符实现双向绑定:
<personal-information v-if="currentSection === 'Public account'" :personal-settings.sync="personalSettings" />
方案3:延迟渲染子组件,确保数据就绪后再挂载
在父组件的子组件v-if条件中,加上数据存在的判断,确保只有当personalSettings有数据时才渲染子组件:
<personal-information v-if="currentSection === 'Public account' && Object.keys(personalSettings).length" :personal-settings="personalSettings" />
这样子组件的mounted钩子执行时,personalSettings已经是完整的对象,直接赋值给personalInfo就能正常显示数据了。
内容的提问来源于stack exchange,提问作者dokichan




