You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue3通过props传递对象后触发TypeError问题求助

Vue3组件访问Props属性时出现TypeError问题分析与解决

我有一个Vue3页面和Vue3组件,页面通过Firebase/Firestore的composable获取数据,将对象作为props传递给组件,但在组件的script setup中访问props属性时触发TypeError,相关代码和报错如下:

useProfiles 代码

import { ref } from 'vue'
import { db } from "/@src/composable/useFirebase"

import {
    doc,
    onSnapshot,
} from "firebase/firestore";

export const profile = ref({});

export const getProfile = async (id) => {
  const unsub = onSnapshot(doc(db, "profiles", id), { includeMetadataChanges: true }, (doc) => {
    profile.value = doc.data()
    profile.value['id'] = doc.id
  });
};

Vue页面代码

<script setup lang="ts">
import { getProfile, profile } from '/@src/composable/useProfiles'

const params = new URL(location.href).searchParams.get('id')

onMounted(async () => { 
  getProfile(params);
})

</script>

<template>
  <div class="page-content-inner">
    <Core-MyProfile v-if="!params" />
    <Core-UserProfile v-if="params" :profile="profile"/>
  </div>
</template>

Vue组件代码

<script setup lang="ts">
import { computed, ref, onMounted } from "vue";

const props = defineProps({
  profile: {
    type: Object,
    required: true,
  },
})

const sellPoints = props.profile.tribute.sell.current
const timePoints = props.profile.tribute.time.current
const usePoints = props.profile.tribute.use.current

const totalPoints = computed(
  () => sellPoints+timePoints+usePoints
);

</script>

报错信息

runtime-core.esm-bundler.js:38 [Vue warn]: Invalid prop: type check failed for prop "profile". Expected Object, got Undefined  
  at <CoreUserProfile key=1 profile=undefined > 
  at <Index onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< undefined > key="/profile?id=FC9gNTJ7D2hMaBcna9ILTGyxB3E2" > 
  at <BaseTransition mode="out-in" appear=false persisted=false  ... > 
  at <Transition name="fade-fast" mode="out-in" > 
  at <RouterView> 
  at <HomeLayout> 
  at <Profile onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< undefined > > 
  at <BaseTransition mode="out-in" appear=false persisted=false  ... > 
  at <Transition name="fade-slow" mode="out-in" > 
  at <RouterView> 
  at <App>

---

runtime-core.esm-bundler.js:38 [Vue warn]: Unhandled error during execution of setup function 
  at <CoreUserProfile key=1 profile=undefined > 
  at <Index onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< undefined > key="/profile?id=0TCIgQZxy5YJqyXNMZQqkBQhZv13" > 
  at <BaseTransition mode="out-in" appear=false persisted=false  ... > 
  at <Transition name="fade-fast" mode="out-in" > 
  at <RouterView> 
  at <HomeLayout> 
  at <Profile onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< undefined > > 
  at <BaseTransition mode="out-in" appear=false persisted=false  ... > 
  at <Transition name="fade-slow" mode="out-in" > 
  at <RouterView> 
  at <App>

---

Core-UserProfile.vue:12 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'tribute')
    at setup (Core-UserProfile.vue:12:34)
    at callWithErrorHandling (runtime-core.esm-bundler.js:155:22)
    at setupStatefulComponent (runtime-core.esm-bundler.js:7165:29)
    at setupComponent (runtime-core.esm-bundler.js:7120:11)
    at mountComponent (runtime-core.esm-bundler.js:5473:13)
    at processComponent (runtime-core.esm-bundler.js:5448:17)
    at patch (runtime-core.esm-bundler.js:5038:21)
    at mountChildren (runtime-core.esm-bundler.js:5234:13)
    at mountElement (runtime-core.esm-bundler.js:5143:17)
    at processElement (runtime-core.esm-bundler.js:5115:13)

问题原因

  1. 异步加载导致初始值缺失:getProfile依赖Firestore的异步回调,页面渲染时profile可能还未获取到数据,甚至出现undefined,导致prop类型校验失败。
  2. 直接访问深层属性无容错:组件在setup阶段直接读取props.profile.tribute,但此时props.profile可能是空对象或undefined,触发读取属性的TypeError。
  3. 模板渲染条件不严谨:仅通过params判断渲染组件,未考虑profile是否加载完成,导致组件在数据就绪前就已初始化。

解决步骤

1. 给profile设置合理初始结构

修改useProfiles,提前定义好数据结构,避免后续访问深层属性报错:

export const profile = ref({
  tribute: {
    sell: { current: 0 },
    time: { current: 0 },
    use: { current: 0 }
  }
});

2. 组件中增加属性访问容错

组件中改用可选链操作符,结合computed处理数据,避免直接访问深层属性:

<script setup lang="ts">
import { computed } from "vue";

const props = defineProps({
  profile: {
    type: Object,
    required: true,
    default: () => ({
      tribute: {
        sell: { current: 0 },
        time: { current: 0 },
        use: { current: 0 }
      }
    })
  },
})

const totalPoints = computed(() => {
  const sell = props.profile?.tribute?.sell?.current || 0;
  const time = props.profile?.tribute?.time?.current || 0;
  const use = props.profile?.tribute?.use?.current || 0;
  return sell + time + use;
});
</script>

3. 优化页面渲染条件

页面模板中增加profile加载完成的判断,确保数据就绪后再渲染组件:

<template>
  <div class="page-content-inner">
    <Core-MyProfile v-if="!params" />
    <div v-if="params && !profile.id">加载中...</div>
    <Core-UserProfile v-if="params && profile.id" :profile="profile"/>
  </div>
</template>

4. 给composable添加加载状态(可选)

在useProfiles中增加加载状态,更精准控制页面渲染:

import { ref } from 'vue'
import { db } from "/@src/composable/useFirebase"
import { doc, onSnapshot } from "firebase/firestore";

export const profile = ref({
  tribute: {
    sell: { current: 0 },
    time: { current: 0 },
    use: { current: 0 }
  }
});
export const isLoading = ref(false);

export const getProfile = async (id) => {
  if (!id) return;
  isLoading.value = true;
  try {
    const unsub = onSnapshot(doc(db, "profiles", id), { includeMetadataChanges: true }, (doc) => {
      profile.value = { ...doc.data(), id: doc.id };
      isLoading.value = false;
    });
    return unsub;
  } catch (err) {
    console.error('加载profile失败:', err);
    isLoading.value = false;
  }
};

页面模板更新为:

<template>
  <div class="page-content-inner">
    <Core-MyProfile v-if="!params" />
    <div v-if="params && isLoading">加载中...</div>
    <Core-UserProfile v-if="params && !isLoading && profile.id" :profile="profile"/>
  </div>
</template>

内容的提问来源于stack exchange,提问作者David Griffin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 17:59:57