I have a component named ProductArea
which displays products loaded from the Prismic API
. The products loaded are dependant on a category
which is selected by the user in a sidebar.
I'm using Vuex
and struggling to come up with a flow that avoids a situation where category
is not yet available in my store ( category
is also loaded from Prismic
).
Here is what the parent of ProductArea
looks like:
<template>
<div>
<NavBar />
<!-- <Header /> -->
<main>
<div v-if="!$fetchState.pending" class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex-1 min-w-0 bg-white xl:flex">
<Sidebar :navigation="navigation" />
<ProductArea />
</div>
</div>
</main>
</div>
</template>
<script lang="ts">
import Vue from 'vue'
import NavBar from '@/components/NavBar.vue'
import Sidebar from '@/components/Sidebar.vue'
import Header from '@/components/Header.vue'
import CategoryHeader from '@/components/CategoryHeader.vue'
import ProductGrid from '@/components/ProductGrid.vue'
import { mapActions } from 'vuex'
import { mapGetters } from 'vuex'
export default {
name: 'App',
components: {
Sidebar,
NavBar,
Header,
CategoryHeader
},
data() {
return {
navigation: null
}
},
async fetch() {
const component = this
await this.fetchCategories()
.then(function(navigationResult) {
const navigation = component.$store.getters.navigation
component.navigation = navigation
})
},
fetchOnServer: true,
methods: {
...mapActions({ fetchCategories: 'fetchCategories', fetchProducts: 'fetchProducts' })
}
}
</script>
I assumed having v-if=".$fetchState.pending"
would prevent ProductArea
from being created until category
has been loaded into the store, however this doesn't seem to be the case.
Here is ProductArea
:
<template>
<div class="bg-white lg:min-w-0 lg:flex-1">
<CategoryHeader :category="this.category" :products="this.products" />
<div class="sm:p-6">
<ProductGrid :category="this.category.primary.category" :products="this.products" />
</div>
</div>
</template>
<script lang="ts">
import { mapActions } from 'vuex'
import { mapGetters } from 'vuex'
import Locale from '@/types/locale'
export default {
name: 'ProductArea',
data() {
return {
category: this.$store.getters.category,
products: Array
}
},
async fetch() {
const component = this
await this.fetchProducts(this.category)
.then(function(productsResult) {
const products = component.$store.getters.products
component.products = products
console.log(products)
})
},
fetchOnServer: true,
methods: {
...mapActions({ fetchProducts: 'fetchProducts' })
}
}
</script>
Here's the error I'm receiving:
Error in fetch(): TypeError: Cannot read property 'products' of undefined
This error is referring to the undefined category
within the fetchProducts
called via fetch
on the ProductsArea
component.
Can anyone point me in the right direction? What would be the optimal flow here to prevent category
being accessed before it is available?
You could set a default category. If you don't want to do that, bring the Vuex category
into the parent and only show <ProductArea>
when it's defined:
Parent
<ProductArea v-if="category" />
computed: {
...mapGetters(['category'])
}
This is necessary because your v-if
on $fetchState.pending
only tests whether all the categories are loaded, but for the child component you also need to test that a category
has been selected.
In fact, you can simplify all your code by mapping the getters instead of storing getters in variables, which is not a good practice. Those variables wouldn't be updated reactively when the getter changes. Instead, completely remove the data
options from both components:
Parent
async fetch() {
await this.fetchCategories();
}
computed: {
...mapGetters(['category', 'navigation'])
}
Child
async fetch() {
await this.fetchProducts();
}
computed: {
...mapGetters(['category', 'products'])
}
Other improvements :
You can shorten the mapActions
calls a bit:
Parent: ...mapActions(['fetchCategories'])
Child: ...mapActions(['fetchProducts'])
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.