I'm getting the error:
"Property "item" was accessed during render but is not defined on instance."
I don't know exactly why, but I was thinking maybe it's because there's an async fetch involved and the template renders before the fetch can be completed?
If that's the case, how do you fix that in Vue3 with "script setup"? I know how to handle that in React, but what is the Vue equivalent to
{item && <Component />}
? I already tried a "v-if" like this:
<div v-if="items" :v-for="item in items">
but that doesn't fix anything. Did I do this wrong? Do I use a lifecycle hook like "beforeMount" or "mounted"? I was under the impression that this wasn't necessary with "script setup"?
If it's not the async fetch thing, did I pass the props wrong? Did I try to render the props wrong? Does it have something to do with using VueX? What causes the "...accessed during render but is not defined on instance" error?
Here's the full code:
store.js
import { createStore } from "vuex";
export default createStore({
state: {
productsArray: [],
checkoutCart: [],
},
mutations: {
ADD_ITEM_TO_CART(state, payload) {
state.checkoutCart.push(payload);
},
INIT_PRODUCTS(state, payload) {
state.productsArray = payload;
},
},
actions: {
cartAdd({ commit }, payload) {
console.log("cartAdd()/payload= ", payload);
commit("ADD_ITEM_TO_CART", payload);
},
getAllProducts({ commit }) {
fetch("http://localhost:5000")
.then((res) => res.json())
.then((data) => {
console.log("data= ", data);
commit("INIT_PRODUCTS", data);
});
},
},
getters: {
getCheckout: (state) => state.checkoutCart,
getProducts: (state) => state.productsArray,
}
});
ParentComponent.vue
<template>
<div >
<h2 >Latest Products</h2>
<div :v-for="item in items">
<ChildComponent :description="item.description" />
</div>
</div>
</template>
<script setup>
import ChildComponent from "../ChildComponent/ChildComponent.vue";
import { useStore } from "vuex";
import { computed } from "vue";
const store = useStore();
const getProducts = async () => {
await store.dispatch("getAllProducts");
};
getProducts();
const items = computed(() => store.getters.getProducts);
</script>
ChildComponent.vue
<template>
<div >
<img src="https://picsum.photos/200/300" alt="" />
<div >
{{ description }}
</div>
</div>
</template>
<script setup>
// eslint-disable-next-line no-undef
defineProps({
description: String,
});
</script>
CodePudding user response:
The error message "Property "item" was accessed during render but is not defined on instance" is likely caused by the fact that the items array is not yet available when the template is first rendered.
In Vue3 with the "script setup", you can use the "computed" property to handle this issue. It allows you to define a computed value that is based on the data from the store, and it will automatically re-render the component when the data is updated.
In your code, you are using a computed property for the items array, which is good. However, you are trying to render the items array before it is defined. To fix this, you should use the v-if directive on the parent div that contains the v-for loop, like this:
This will ensure that the div and its contents are not rendered until the items array is defined and has a value.
Also, you have a syntax error in your template, the v-for directive should be used in the opening tag like this:
<div v-if="items" v-for="item in items">
You can also use the v-show directive if you want to keep the div in the DOM even when items is null or undefined, but it will be hidden.
As an alternative, you can also use lifecycle hooks such as "onMounted" or "setup" to make the async call and set the items array.
It is also worth noting that in the tag of the ParentComponent, you should use import { computed } from 'vue' instead of import { computed } from "vuex".
CodePudding user response:
You can run a console.log on this "items" array to verify that the array is being loaded correctly and your for is reading a populated array!