I am building a page with several components in it, the data for all these components I need to get by making an ajax call. As the child components are being mounted before the data comes in I'm getting undefined errors. Whats the best way to pass the data?
Here is a simplified version of what I'm trying to achieve Stackblitz
In that example I have one Parent.vue and inside that we have 3 child coomponents, ID, Title, Body. After getting the data from API, the child componets are not updating.
Also for making the api calls I am directly calling load method inside setup() is there any better way of doing it?
Code Snippets from the stackblitz link
<template>
<h1>Data from Parent</h1>
{{ post.id }} - {{ post.title }} - {{ post.body }}
<h1>Data from Child</h1>
<IdChild :idP="post.id" />
<TitleChild :titleP="post.title" />
<BodyChild :bodyP="post.body" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
const post = ref()
const load = async () => {
let data = await fetch('https://jsonplaceholder.typicode.com/posts/1')
post.value = await data.json()
}
load()
</script>
CodePudding user response:
When dealing with asynchronous data required in your components, you have basically two options:
- You render the components before you get the data. It can be with default values or a loading state
<template>
<div v-if="!myAsyncData">Loading...</div>
<div v-else>{{ myAsyncData }}</div>
</template>
<script setup>
const myAsyncData = ref(null)
async function load() {
myAsyncData.value = await /* http call */
}
load() // will start to load and rendering the component
</script>
- You await the response in the
setup
hook combined with the<Suspense>
component so it starts to render only when the data is available.
Example (playground):
<!-- App.vue -->
<template>
<Suspense>
<Parent />
</Suspense>
</template>
<!-- Parent.vue -->
<template>
<div>{{ myAsyncData }}</div>
</template>
<script setup>
const myAsyncData = ref(null)
async function load() {
myAsyncData.value = await /* http call */
}
await load() // will wait this before rendering the component. Only works if the component is embebbed within a [`<Suspense>`](https://vuejs.org/guide/built-ins/suspense.html) component.
</script>
CodePudding user response:
In your exemple, you just forgot to import your child components.
See my fork of your exemple : URL