【发布时间】:2021-09-26 10:03:05
【问题描述】:
我有这条路线:
{
path: "/categories/:categorySlug",
name: "product-list",
meta: {
title: "Categories",
},
},
当组件首次加载时,它会拉入类别和与之相关的任何产品。问题是当我更改类别 slug 时,由于某种原因类别更新正常,但产品没有。 我决定添加一个 beforeRouteUpdate 来强制更改产品,我将其设置如下:
export default defineComponent({
name: "ProductList",
components: { Brands, Chooser, Products },
setup() {
const instance = getCurrentInstance();
const searchTerm = computed(() => {
return instance.proxy.$route.params.searchTerm;
});
const {
brands,
brandError,
brandFacets,
brandsLoading,
brandsHasMoreResults,
brandsItemsToShow,
brandsQuery,
brandsTotal,
brandsFetchMore,
} = useSearchBrands(searchTerm, 12, [], true);
const {
category,
categoryError,
categoryLoading,
products,
productError,
productFacets,
productsLoading,
productsHasMoreResults,
productsItemsToShow,
productsQuery,
productsTotal,
productsFetchMore,
} = useListProducts(instance);
return {
brands,
brandError,
brandFacets,
brandsLoading,
brandsHasMoreResults,
brandsItemsToShow,
brandsQuery,
brandsTotal,
category,
categoryError,
categoryLoading,
products,
productError,
productFacets,
productsLoading,
productsHasMoreResults,
productsItemsToShow,
productsQuery,
productsTotal,
brandsFetchMore,
productsFetchMore,
};
},
beforeRouteUpdate(to, from, next) {
console.log(to);
this.productsQuery.refetch();
next();
},
});
乍一看,它似乎没有发生任何事情,因为如果我更改路线,它仍然显示与第一次加载相同的产品。但是如果我再次更改,我注意到它现在显示了之前路线更改的产品:
如果我将路线从 烤箱 更改为 咖啡机,它将显示烤箱。 我不能使用 beforeRouteEnter 因为我无权访问 this 并且使用 beforeRouteLeave 根本不会更新组件,即使在我的日志,我可以看到请求正在改变。
因此,总而言之,当我使用 beforeRouteUpdate 更改路线时,我可以在日志中看到请求更改为正确的类别,并且我可以看到返回的正确产品,但我没有看到组件中的结果,直到我再次更改路线(使用相同的组件)。
有谁知道我该如何解决这个问题?
更新 我被要求显示我的产品列表的代码。我使用 vue apollo,我有两个通用函数,第一个是 useGraphQuery,如下所示:
import { ref } from "vue-demi";
import { useQuery, useResult } from "@vue/apollo-composable";
export function useGraphQuery(params, gql, pathFn, clientId = "apiClient") {
if (!params?.value)
return {
response: ref(undefined),
loading: ref(false),
error: ref(undefined),
query: ref(undefined),
};
// TODO: figure our a way to skip the call if the parameters are null
const { result, loading, error, query, fetchMore } = useQuery(gql, params, {
clientId,
//enabled: !!params?.value,
});
const response = useResult(result, null, pathFn);
return { response, loading, error, query, fetchMore };
}
我所有的 graphql 查询都使用这个。 然后对于搜索(即产品搜索),使用另一个名为 useGraphSearch 的函数:
import { computed } from "@vue/composition-api";
import { useGraphQuery } from "./graph-query";
export function useGraphSearch(params, gql, pathFn) {
const { response, loading, error, query, fetchMore } = useGraphQuery(
params,
gql,
pathFn
);
const items = computed(() => {
if (!response.value) return [];
return response.value.items;
});
const facets = computed(() => {
if (!response.value) return [];
return response.value.facets;
});
const total = computed(() => {
if (!response.value) return 0;
return response.value.total;
});
const hasMoreResults = computed(() => {
if (!response.value) return false;
return response.value.hasMoreResults;
});
const itemsToShow = computed(() => params.value.search.itemsToShow);
const more = () => {
useGetMore(params.value, fetchMore);
};
return {
error,
facets,
hasMoreResults,
items,
itemsToShow,
loading,
query,
total,
more,
};
}
function useGetMore(params, fetchMore) {
params.search.page++;
fetchMore({
variables: params,
});
}
在我之前提到的路线上,有 3 个查询正在运行。其中一个似乎无需做任何事情就可以工作。这就是 useGetCategory,它看起来像这样:
import { computed } from "@vue/composition-api";
import * as getCategoryBySlug from "@graphql/api/query.category.gql";
import { useGraphQuery } from "./graph-query";
export function useGetCategory(instance) {
const params = computed(() => {
const route = instance.proxy.$route;
const slug = route.params.categorySlug;
if (!slug) return;
return { slug };
});
const { response, error, loading } = useGraphQuery(
params,
getCategoryBySlug,
(data) => data.categoryBySlug
);
return { category: response, categoryError: error, categoryLoading: loading };
}
无论我是否调用了 beforeRouteUpdate 都会更新。 第二个是 useListProducts,如下所示:
import { ComponentInternalInstance } from "@vue/composition-api";
import { useSearchCategoryProducts } from "@logic/search-products";
import { useTrackProductImpressions } from "@logic/track-product-impressions";
import { useTrackProductClick } from "@/_shared/logic/track-product-click";
export function useListProducts(instance: ComponentInternalInstance) {
const {
products,
productError,
productFacets,
productsLoading,
productsHasMoreResults,
productsItemsToShow,
productsQuery,
productsTotal,
productsFetchMore,
} = useSearchCategoryProducts(instance);
return {
products,
productError,
productFacets,
productsLoading,
productsHasMoreResults,
productsItemsToShow,
productsQuery,
productsTotal,
productsFetchMore,
};
}
正如您在此处看到的,这调用了 useSearchCategoryProducts,它仅用于创建参数,如下所示:
export function useSearchCategoryProducts(
instance: ComponentInternalInstance,
orderBy = [{ key: "InVenue", value: "desc" }]
) {
const params = computed(() => {
const slug = instance.proxy.$route.params.categorySlug;
if (!slug) return;
const filters = createFilters("CategorySlug", [slug]);
const request = createRequest(defaultParameters, 1, filters, orderBy);
return { search: request };
});
return queryProducts(params);
}
function queryProducts(params) {
console.log(params);
const {
error,
facets,
hasMoreResults,
items,
itemsToShow,
loading,
query,
total,
more,
} = useGraphSearch(params, searchProducts, (data) => data.searchProducts);
return {
products: items,
productError: error,
productsLoading: loading,
productFacets: facets,
productsHasMoreResults: hasMoreResults,
productsItemsToShow: itemsToShow,
productsTotal: total,
productsQuery: query,
productsFetchMore: more,
};
}
您可以在私有函数 queryProducts 中看到 console.log,我可以看到参数正在更新。 我知道这需要考虑很多,但我已经创建了 useGraphQuery 和 useGraphSearch,因此我可以确保我创建的每个查询都是相同的,并且应该在相同的情况下工作方式。 useGetCategory 和 useListProducts 工作方式不同的原因(即当路线改变时类别改变,但产品列表没有改变)超出了我的理解范围这就是我尝试实现 beforeRouteUpdate 的原因。
设置代码如下所示:
import {
computed,
defineComponent,
getCurrentInstance,
} from "@vue/composition-api";
import Brands from "@components/brands/brands.component.vue";
import Chooser from "@components/chooser/chooser.component.vue";
import Products from "@components/products/products.component.vue";
import { useListProducts } from "./list-products";
import { useSearchBrands } from "@logic/search-brands";
import { useGetCategory } from "@logic/get-category";
export default defineComponent({
name: "ProductList",
components: { Brands, Chooser, Products },
setup() {
const instance = getCurrentInstance();
const searchTerm = computed(() => {
return instance.proxy.$route.params.categorySlug;
});
const { category, categoryError, categoryLoading } =
useGetCategory(instance);
const {
brands,
brandError,
brandFacets,
brandsLoading,
brandsHasMoreResults,
brandsItemsToShow,
brandsQuery,
brandsTotal,
brandsFetchMore,
} = useSearchBrands(searchTerm, 12, [], true);
const {
products,
productError,
productFacets,
productsLoading,
productsHasMoreResults,
productsItemsToShow,
productsQuery,
productsTotal,
productsFetchMore,
} = useListProducts(instance);
return {
brands,
brandError,
brandFacets,
brandsLoading,
brandsHasMoreResults,
brandsItemsToShow,
brandsQuery,
brandsTotal,
category,
categoryError,
categoryLoading,
products,
productError,
productFacets,
productsLoading,
productsHasMoreResults,
productsItemsToShow,
productsQuery,
productsTotal,
brandsFetchMore,
productsFetchMore,
};
},
beforeRouteUpdate(to, from, next) {
console.log(to);
this.brandsQuery.refetch();
this.productsQuery.refetch();
next();
},
});
【问题讨论】:
标签: vuejs2 vue-composition-api