Vue父子组件传值异常:FavoriteButton.vue接收Props为undefined
解决Vue父子组件传值时子组件
created钩子中props未初始化的问题 我看了你遇到的问题:父组件Product.vue给FavoriteButton.vue传值,但子组件created里打印this.item全是undefined,其他子组件却正常。这问题其实是Vue组件生命周期的小坑,我帮你梳理下原因和解决办法:
问题根源
你在FavoriteButton.vue的data里直接用this.productId这类props去初始化item对象,但Vue组件的props是在实例创建完成后(created钩子之前的阶段)才被注入到实例中的,而data的初始化是在更早的阶段(beforeCreate之后、created之前),这时候props还没赋值,所以item里的所有属性自然都是undefined。
而其他子组件(比如Modal、MapProduct)没问题,大概率是它们没有在这么早的阶段就直接依赖props初始化数据,而是在模板里直接使用props,或者在mounted之后才使用,这时候props已经完全初始化了。
解决方案
1. 把item改成计算属性(推荐)
计算属性会自动响应props的变化,而且能确保你拿到的是最新的props值,完全避免初始化时机的问题:
修改FavoriteButton.vue的代码:
<template> <div> <p><i v-if="fav" class="far fa-heart" @click.prevent="addFav"></i></p> <p><i v-if="!fav" class="fas fa-heart" @click.prevent="deleteFav"></i></p> </div> </template> <script> import fireApp from '@/plugins/firebase' const firebase = require("firebase"); require("firebase/firestore"); const db = firebase.firestore(); import store from '../store' import { mapGetters } from 'vuex' export default { name: "FavoriteButton", data() { return { fav: true // 删掉原来的item定义 } }, props: { productId: String, quantity: String, sale: String, business: String, address: String, uid: String, email: String, limitObject: String, limit: [String, Number] // 注意:你定义了numberOfOrders和count,但父组件没传,这两个会一直是undefined,记得补传或者删掉 }, computed: { // 用计算属性生成item item() { return { productId: this.productId, numberOfOrders: this.numberOfOrders, // 父组件未传递,需确认是否需要 uid: this.uid, email: this.email, sale: this.sale, business: this.business, address: this.address, limitObject: this.limitObject, limit: this.limit, count: this.count // 父组件未传递,需确认是否需要 } } }, created() { fireApp.auth().onAuthStateChanged((user) => { if (user) { console.log(this.item); // 现在能拿到正确的值了 // 注意:你原来的查询用this.item作为product_id的匹配值,应该是用productId吧? const product = this.item.productId; const userId = fireApp.auth().currentUser.uid; const favoriteCollection = db.collection('Favorite').doc(userId).collection('FavoriteProducts').where("product_id", "==", product); favoriteCollection.get().then((querySnapshot) => { // 优化判断逻辑:只要有查询结果,就说明已收藏 this.fav = querySnapshot.size === 0; // 等价于你原来的逻辑:有doc存在则fav=false,否则fav=true }) } }); }, methods: { addFav() { this.$store.dispatch('createFav', this.item) // 这里也换成this.item this.fav = false }, deleteFav() { this.$store.dispatch('deleteFav', this.item) // 换成this.item this.fav = true }, } } </script>
2. 若要保留data,则在created中赋值
如果你不想用计算属性,也可以在created钩子中给item赋值,这时候props已经注入完成了:
data() { return { fav: true, item: {} // 先初始化空对象 } }, created() { // 先给item赋值 this.item = { productId: this.productId, uid: this.uid, email: this.email, sale: this.sale, business: this.business, address: this.address, limitObject: this.limitObject, limit: this.limit }; // 再执行Firestore逻辑 fireApp.auth().onAuthStateChanged((user) => { // ...后续代码 }) }
额外注意点
- 你子组件定义的
numberOfOrders和count两个props,父组件Product.vue并没有传递,这两个值会一直是undefined,记得要么在父组件补传,要么删掉这两个没用的props。 - 原来的Firestore查询遍历
querySnapshot的逻辑可以优化,直接用querySnapshot.size判断是否有收藏记录,避免多次修改fav值的问题。
内容的提问来源于stack exchange,提问作者Yohei Umezu
相关产品推荐
相关产品推荐

