在Pinia Store中使用Nuxt Apollo获取产品详情的实现问题
问题根源
你踩了两个核心坑:
getProductData是异步函数,调用后返回的是Promise对象,不是直接的产品数据,Vue的computed属性没法自动等待Promise完成并解析结果,所以页面要么显示Promise的字符串形式,要么因为逻辑判断返回null- 当前的computed写法会在每次依赖变化时重复调用
getProductData,导致多次发起请求,同时isLoading的状态会被频繁重置,逻辑完全混乱
修正方案
第一步:重构Pinia Store,用响应式变量存数据
把异步请求的结果存在Store的响应式变量里,而非每次调用都返回Promise:
//using composition api in Pinia import { ref } from 'vue'; import { defineStore } from 'pinia'; export const useProductStore = defineStore('product', () => { const config = useRuntimeConfig(); const isLoading = ref(false); // 新增响应式变量存储产品数据 const productData = ref(null); const getProductData = async (id) => { // 优化:如果已加载过该ID的数据,直接返回避免重复请求 if (productData.value?.product?.id === `gid://shopify/Product/${id}`) { return; } isLoading.value = true try { const query = gql` query GetProductsById($id: ID!) { product(id: $id) { id title vendor publishedAt handle variants(first: 100) { nodes { id title price { amount } image { url altText width height } } } } } ` const variables = { id: "gid://shopify/Product/" + id, } const results = await useAsyncQuery(query, variables); // 将结果存入响应式变量,而非直接返回 productData.value = results; isLoading.value = false } catch (err) { console.error('加载产品失败:', err); productData.value = null; isLoading.value = false } }; // 把productData也暴露给外部使用 return { getProductData, isLoading, productData }; });
第二步:修改页面逻辑,主动触发请求并读取响应式数据
页面不再依赖computed处理异步,而是在路由参数变化时主动调用Store的请求方法,直接读取Store里的响应式数据:
<template> <div class="bg-white"> <div v-if="isLoading">加载中...</div> <div v-else>{{ JSON.stringify(productData) }}</div> </div> </template> <script setup> import { watch, onMounted } from 'vue' import { storeToRefs } from 'pinia'; import { useProductStore } from '../stores/product-store'; import { useRoute } from 'vue-router' const route = useRoute(); const productStore = useProductStore(); // 将Store中的响应式变量转为页面可用的ref const { isLoading, productData } = storeToRefs(productStore); // 定义加载产品的方法 const loadProduct = async () => { const productId = route.query.id; if (productId) { await productStore.getProductData(productId); } }; // 页面挂载时首次加载产品 onMounted(() => { loadProduct(); }); // 监听路由ID变化,切换产品时重新加载 watch(() => route.query.id, () => { productData.value = null; loadProduct(); }); </script>
关键改动说明
- Store新增
productData响应式变量,异步请求完成后更新它,确保页面能实时响应数据变化 - 页面通过
storeToRefs获取productData的响应式引用,直接在模板中使用 - 用
onMounted和watch主动触发请求,computed仅适合同步计算逻辑,不处理异步 - 增加重复请求判断,避免同一产品被多次请求
内容的提问来源于stack exchange,提问作者Qiuzman
相关产品推荐
相关产品推荐

