0

I have Nuxt page for products list with fetchProducts() method from pinia store.

The problem is that product list NOT rendered on page 1st visit.

<script setup>
import { storeToRefs}   from "pinia";
import { useShopStore } from '@/stores/shop'

const shop = useShopStore();
shop.fetchProducts();
const {products} = storeToRefs(shop)
const hasProducts = computed(() => products.value.length > 0);

</script>

<template>
    <NuxtLayout>
        <div class="container">
            <h2>Products</h2>
            <div class="container" v-if="hasProducts">
                  <div class="row row-cols-1 gap-3">
                    <ProductCard :product="product" v-for="product in products" :key="product.id"/>
                </div>
            </div>
            <div v-else>
                <h3>Products NOT loaded</h3><br>
            </div>
        </div>
    </NuxtLayout>
</template>

As you can see on following snapshot products are loaded and available in pinia store, but array products on page is empty.

enter image description here

If I go back to home and return to product page products are rendered without any problem or warnings in console.

Any suggestion what I can do to fix or even investigate the issue?

PS. Store code if it's matter here

import { defineStore } from 'pinia'

import Product  from "@/models/Product";

export const useShopStore = defineStore('shop', {
    state: () => ({
        //products: <Product[]>[]
        products: [] as Product[]
    }),
    actions: {
        fetchProducts: async function () {
            try {
                const {data} = await useFetch('https://fakestoreapi.com/products');
                //TODO - fix this  typescript error `TS2352: Conversion of type 'Ref<unknown>' to type 'Product[]' may be a mistake because neither type sufficiently overlaps with the other.`
                // @ts-ignore
                this.products = data as Product[];
            } catch (error) {
                return error
            }
        },
    }
})
AlexeiP
  • 581
  • 1
  • 10
  • 26
  • does it work if you fetch in `script setup` (not in store)? – Orbis Jul 02 '23 at 16:36
  • @Orbis I do call shop.fetchProducts(); from `script setup` which is working. I mean store.products are loaded (please see snapshot) – AlexeiP Jul 02 '23 at 16:38
  • FYI: typescript error `TS2352` by using `await useFetch(...)` – Orbis Jul 02 '23 at 16:40
  • @Orbis. Thank you for note that. Can you tell me more about TS2352? Is it a problem with `await`? – AlexeiP Jul 02 '23 at 16:42
  • 1
    TL;DR: typecasting should only be used if you can't solve it with generics. In this case TS knows, that `Ref` does not overlap with `Product[]`. The reason: `data` seems to be an `ref` and `Product` is not. `this.products = data as Ref` might work too. – Orbis Jul 03 '23 at 09:08

1 Answers1

0

I'm not sure how valid it is, but assign this.products = data.value as Product[]; instead of this.products = data as Product[]; seems to fix the issue.

fetchProducts: async function () {
  try {
    
    // TODO - fix this  typescript error `TS2352: Conversion of type 'Ref<unknown>' to type 'Product[]' may be a mistake because neither type sufficiently overlaps with the other.`  // @ts-expect-error

        // NOTE: OPTION 1, with useFetch() -> require import
        const { data } = await useFetch('https://fakestoreapi.com/products')
        this.products = (await data.value) as Product[]

        // NOTE: OPTION 2, with fetch()
        // const response = await fetch('https://fakestoreapi.com/products')
        // this.products = (await response.json()) as Product[]
  } catch (error) {
    return error
  }
}

Please let me know if it's a good solution or not. I'm still learning Vue 3 and Nuxt 3 and not sure that using useFetch inside pinia store is a good idea.

Gustavo IAS
  • 118
  • 5
AlexeiP
  • 581
  • 1
  • 10
  • 26
  • data is a `Ref`. Not just the `response.data`. – Orbis Jul 03 '23 at 09:10
  • Although it is a valid solution, according to the nuxt doc: "useFetch is a composable meant to be called directly in a setup function, plugin, or route middleware..."(https://nuxt.com/docs/api/composables/use-fetch ); I think that useFetch would be better used in a somePage.vue, so I would take advantage of values returned {pending,...} which applies in your specific case using hasProducts, which you will get a better idea with (https://nuxt.com /docs/getting-started/data-fetching#lazy) – Gustavo IAS Jul 04 '23 at 00:33
  • 1
    If you want to use the flux pattern (base of Vuex, predecessor of Pinia) and it is possible that those who come from Vuex want to make their requests to the API in Store, it would be better to use fetch / axios so that they get along better take advantage of the resources that you offers each option, e.g. have a custom handleRequests. While UseFetch can be used in Store (Pinia), you might encounter some bugs, as you can check in codesandbox (https://codesandbox.io/p/sandbox/old-sea-lc2mq5?file=%2Fpages%2Findex.vue%3A1%2C1); where is also the demo to specifically solve the current question. – Gustavo IAS Jul 04 '23 at 00:35
  • @GustavoIAS Thanks. I came from Vuex/axios where I haven't had such problems. Now I'm learning Nuxt with Pinia and having lot of surprises. ))) – AlexeiP Jul 04 '23 at 18:23