Vue2 onServerPrefetch вызывается, когда нет экземпляра активного компонента, с которым можно было бы связать apollo

#vuejs2 #vue-composition-api #vue-apollo

Вопрос:

Возможно, это из-за недостатка знаний, но я, похоже, сталкиваюсь с этой проблемой, что бы я ни делал. У меня есть этот компонент, который я хочу запрашивать всякий раз, когда изменяется пуля маршрута. Изначально все было устроено так:

 import {
  computed,
  defineComponent,
  getCurrentInstance,
  ref,
} 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 request = computed(() => {
      return {
        searchTerm: "*",
        itemsToShow: 12,
        filters: [
          {
            key: "Categories[]/Slug",
            value: `'${instance.proxy.$route.params.categorySlug}'`,
          },
        ],
        includePartialMatches: false,
      };
    });
    const orderBy = ref([
      { key: "InVenue", value: "desc" },
      { key: "Promoted", value: "desc" },
    ]);

    const { category, categoryError, categoryLoading } =
      useGetCategory(instance);

    const {
      brands,
      brandError,
      brandFacets,
      brandsLoading,
      brandsHasMoreResults,
      brandsItemsToShow,
      brandsTotal,
      brandsFetchMore,
      brandsRefetch,
    } = useSearchBrands(request);

    const {
      products,
      productError,
      productFacets,
      productsLoading,
      productsHasMoreResults,
      productsItemsToShow,
      productsTotal,
      productsFetchMore,
      productsRefetch,
    } = useListProducts(instance, orderBy);

    return {
      brands,
      brandError,
      brandFacets,
      brandsLoading,
      brandsHasMoreResults,
      brandsItemsToShow,
      brandsTotal,
      category,
      categoryError,
      categoryLoading,
      products,
      productError,
      productFacets,
      productsLoading,
      productsHasMoreResults,
      productsItemsToShow,
      productsTotal,
      brandsFetchMore,
      productsFetchMore,
      brandsRefetch,
      productsRefetch,
    };
  },
});
 

Похоже, это работает, когда я меняю маршруты, все меняется, как и ожидалось. Но у меня включено отслеживание, и я вижу, что при переходе на родительскую страницу (в данном случае на продукты) код снова срабатывает, но с нулевым значением, что нехорошо.
Итак, я изменил свой код на этот:

 import {
  computed,
  defineComponent,
  getCurrentInstance,
  reactive,
  ref,
  toRefs,
  watch,
} 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 categoryResult = reactive({
      category: null,
      categoryError: null,
      categoryLoading: null,
    });
    const brandsResult = reactive({
      brands: [],
      brandError: null,
      brandFacets: [],
      brandsLoading: false,
      brandsHasMoreResults: false,
      brandsItemsToShow: null,
      brandsTotal: 0,
      brandsFetchMore: null,
      brandsRefetch: null,
    });
    const productsResult = reactive({
      products: [],
      productError: null,
      productFacets: [],
      productsLoading: false,
      productsHasMoreResults: false,
      productsItemsToShow: null,
      productsTotal: 0,
      productsFetchMore: null,
      productsRefetch: null,
    });

    const list = (slug) => {
      if (!slug) return;
      const request = ref({
        searchTerm: "*",
        itemsToShow: 12,
        filters: [
          {
            key: "Categories[]/Slug",
            value: `'${slug}'`,
          },
          {
            key: "InnovationGuide",
            value: "true",
          },
        ],
        includePartialMatches: false,
      });
      const orderBy = ref([
        { key: "InVenue", value: "desc" },
        { key: "Promoted", value: "desc" },
      ]);

      Object.assign(brandsResult, useSearchBrands(request));
      Object.assign(categoryResult, useGetCategory(instance));
      Object.assign(productsResult, useListProducts(instance, orderBy));
    };

    watch(
      () => instance.proxy.$route.params.categorySlug,
      (slug) => list(slug)
    );

    list(instance.proxy.$route.params.categorySlug);

    return {
      ...toRefs(brandsResult),
      ...toRefs(categoryResult),
      ...toRefs(productsResult),
    };
  },
});
 

Again, this looks like it works. I don’t have the issue between child and parent anymore, but the problem is, if I navigate from /products/speakers to /products/cameras I get this error:

[![enter image description here][1]][1]

I have tried many many many times to fix this and I have never been able to. It seems that vue apollo is not great and the documentation is far from perfect.
Currently, I have it setup like this:

 import { useGetUser } from "@logic/get-user";
import {
  ApolloClient,
  InMemoryCache,
  createHttpLink,
} from "@apollo/client/core";
import { setContext } from "@apollo/client/link/context";

const uri = `${process.env.VUE_APP_API_URL}/graphql`;
const link = createHttpLink({
  uri,
});

const cache = new InMemoryCache();

const authLink = setContext(async (_, { headers }) => {
  const user = useGetUser();
  const token = user ? `Bearer ${user.token}` : "";

  if (!token) return { headers: { ...headers } };
  return {
    headers: {
      ...headers,
      authorization: token || "",
    },
  };
});

const apiClient = new ApolloClient({
  link: authLink.concat(link),
  cache,
});

export default apiClient;
 

which in my main.ts I register like this:

 import apiClient from "./_core/plugins/vue-apollo-api";

new Vue({
  router,
  store,
  vuetify,
  setup() {
    provide(ApolloClients, {
      default: apiClient,
      apiClient,
      contentfulClient,
    });
  },

  render: (h) => h(App),
}).$mount("#app");
 

If I try to add:

 import VueApollo from "vue-apollo";
const apolloProvider = new VueApollo({
  clients: {
    apiClient,
    contentfulClient
  },
  defaultClient: apiClient
});
 

I get a whole load of errors stating:

1: Type ApolloClient is missing the following properties from type ‘ApolloClient’: store, writeData, initQueryManager
2: Type ‘ApolloClient’ is not assignable to type ‘ApolloClient’

But no matter how many pages I search and use, I can never get this to work.

Can someone please help as it’s stopping production now and tbh, I wish I had never bothered with graphql because of it.
[1]: https://i.stack.imgur.com/oqq59.png