【问题标题】:vue2 composition api beforeRouteUpdate updating after the route changesvue2 composition api beforeRouteUpdate 路由变化后更新
【发布时间】: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,我可以看到参数正在更新。 我知道这需要考虑很多,但我已经创建了 useGraphQueryuseGraphSearch,因此我可以确保我创建的每个查询都是相同的,并且应该在相同的情况下工作方式。 useGetCategoryuseListProducts 工作方式不同的原因(即当路线改变时类别改变,但产品列表没有改变)超出了我的理解范围这就是我尝试实现 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


    【解决方案1】:

    您没有在路由更新处理程序中使用to。如果您的加载代码取决于路线,它将具有先前的信息,因为事件发生之前它被更新。

    您需要将有关 to 路由的信息提供给正在执行加载的代码,或使用 after 事件。

    【讨论】:

    • 我不确定你的意思? “to”路由在更改路由时已经包含参数,refetch 方法使用该参数获取数据。你说的事后事件是什么意思?这和 beforeRouteLeave 有什么不同吗?
    • @r3plica 它是如何使用的?您使用零参数调用该函数。它会在哪里得到to?包括所有必要的代码
    • 在设置代码中,我创建了一个接受 categorySlug 的 params 计算属性。 refetch 方法使用该计算属性,我可以看到这些值是正确的
    • @r3plica 那么你能包含那个代码吗?无法说出我们看不到的代码和无法验证的值有什么问题
    • 是的,但我必须警告你,这是 vue apollo,到目前为止我提出的任何问题似乎都难倒人们:(
    【解决方案2】:

    所以我设法解决了这个问题。这取决于我的缓存策略。 我一直在这样做:

    const typePolicy = {
      keyArgs: ["search", ["page", "skip"]],
      // Concatenate the incoming list items with
      // the existing list items.
      merge(existing: any = {}, incoming: any) {
        const items = (existing.items ? existing.items : []).concat(incoming.items);
        const item = { ...existing, ...incoming };
        item.items = items;
        return item;
      },
    };
    
    const cache = new InMemoryCache({
      typePolicies: {
        Query: {
          fields: {
            searchCategories: typePolicy,
            searchBrands: typePolicy,
            searchPages: typePolicy,
            searchProducts: typePolicy,
          },
        },
      },
    });
    

    所以我的分页结果总是附加到我当前的列表中,但由于某种原因导致了问题。当我换成这个时:

    const cache = new InMemoryCache();
    

    我的问题已经解决了。

    【讨论】:

      猜你喜欢
      • 2021-09-17
      • 2021-03-16
      • 1970-01-01
      • 2018-08-20
      • 1970-01-01
      • 2015-06-23
      • 2022-12-12
      • 2021-06-22
      • 2021-06-23
      相关资源
      最近更新 更多