I want to fetch some products from api, the issue is that the template will not wait for the async function to run and for the products
prop to be filled with data fetched, as its an async function, so the value of products
will be null when the template runs and products.value
will give error cannot read properties of null (reading 'value')
, so i used v-if
to check if there are products before trying to display them, but it displays nothing, as it doesn't catch the change been made to products
prop after getting the data, in react
with useEffect api
i could pass an array of dependencies and sepicify products
state to make the update happens, what is the equivalent in vue
? thanks in advance
Route::get('/products',function(){
$products = DB::table('products')->get()->toArray();
return response()->json([
'products' => $products,
]);
});
import { ref, watchEffect } from "vue";
const products = ref(null);
watchEffect(() => {
fetch("/products")
.then((response) => response.json())
.then((data) => (products.value = data));
});
<template>
<div v-if="products">
<ul v-for="product in products.value">
<li class="py-4 px-2">
<Link href="...">
<img :src="product.imageUrl"/>
<p>{{ product.name }}</p>
</Link>
</li>
</ul>
</div>
</template>
Just use <ul v-for="product in products">
.
Refs are unwrapped automatically in templates. So initially you are trying to get (null).value
.
Also you don't need watchEffect()
(there's no reactive dependencies inside it), just do the fetch in the component's root.
I also suggest to avoid using refs for non-primitives. That way you can avoid unwrapping refs in the script secion.
You can also omit <div v-if="products">
since initially products
is an empty array:
import { reactive, onMounted } from "vue";
const products = reactive([]);
onMounted(async () => products.push(...await(await fetch("/products")).json()));
<template>
<ul v-for="product in products">
<li class="py-4 px-2">
<Link href="...">
<img :src="product.imageUrl"/>
<p>{{ product.name }}</p>
</Link>
</li>
</ul>
</template>