Vue3中如何正确将异步数据传递给子组件?
解决Vue父组件异步数据传递给子组件的未定义错误
问题说明
父组件在onMounted钩子中异步获取数据后传递给子组件,子组件抛出错误:TypeError: Cannot read properties of undefined (reading 'startDateTime'),核心原因是异步数据加载未完成时,子组件已完成初始化,此时传入的props为undefined,同时父组件还存在异步函数赋值错误的问题。
现有代码
父组件代码
<script setup lang="ts"> import { ref, onMounted } from 'vue'; import TestForm from '../components/TestForm.vue'; const testMe = ref(); // testMe.value = { // id: 1, // startDateTime: '2023-06-26T09:43:32.203Z', // }; onMounted(() => { // 错误:async函数直接赋值会得到Promise,而非实际数据 const newObject2 = fetchData(); console.log('onMounted testing newObject2', newObject2); testMe.value = newObject2; }); async function fetchData() { const res = await fetch('http://localhost:4000/testMes'); const data = await res.json(); const newObject = data[0]; console.log('testing the async function data from json:', newObject); return newObject; } </script> <template> <div> <TestForm :testProps="testMe" /> </div> </template>
子组件TestForm.vue代码
<script setup lang="ts"> import { ref } from 'vue'; const props = defineProps(['testProps']); const startDateTime = ref(''); // 错误:初始化时props.testProps为undefined,直接访问startDateTime抛出异常 // eslint-disable-next-line vue/no-setup-props-destructure startDateTime.value = props.testProps.startDateTime; </script> <template> <div> {{ startDateTime }} </div> </template>
正确实现方案
第一步:修复父组件的异步数据赋值
fetchData是异步函数,直接赋值会将Promise对象传给testMe,需要用await等待异步操作完成,同时把onMounted回调改为async函数:
<script setup lang="ts"> import { ref, onMounted } from 'vue'; import TestForm from '../components/TestForm.vue'; const testMe = ref(); onMounted(async () => { // 用await等待异步函数返回实际数据 const newObject2 = await fetchData(); console.log('onMounted testing newObject2', newObject2); testMe.value = newObject2; }); async function fetchData() { const res = await fetch('http://localhost:4000/testMes'); const data = await res.json(); const newObject = data[0]; console.log('testing the async function data from json:', newObject); return newObject; } </script> <template> <div> <TestForm :testProps="testMe" /> </div> </template>
第二步:子组件处理未定义场景
提供三种可选方案,根据实际需求选择:
方案1:使用可选链+监听props变化
通过可选链?.避免undefined报错,同时用watch监听props更新,确保数据同步:
<script setup lang="ts"> import { ref, watch } from 'vue'; const props = defineProps(['testProps']); const startDateTime = ref(''); // 初始化时用可选链安全访问 startDateTime.value = props.testProps?.startDateTime || ''; // 监听props变化,实时更新本地ref watch(() => props.testProps, (newVal) => { startDateTime.value = newVal?.startDateTime || ''; }, { immediate: true }); </script> <template> <div> {{ startDateTime }} </div> </template>
方案2:模板中直接使用可选链
如果不需要将props值存储到本地ref,可直接在模板中处理,简化代码:
<script setup lang="ts"> defineProps(['testProps']); </script> <template> <div> {{ testProps?.startDateTime || '' }} </div> </template>
方案3:父组件中条件渲染子组件
在父组件中,仅当testMe有值时才渲染子组件,确保子组件初始化时props已存在有效数据:
<template> <div> <TestForm :testProps="testMe" v-if="testMe" /> </div> </template>
内容的提问来源于stack exchange,提问作者Samuel
相关产品推荐
相关产品推荐

