r3plica
r3plica

Reputation: 13367

Refresh my Vue Apollo query when params change

I am new to vue, but I don't understand why no one seems to be able to answer this question. I would have thought it was simple, but I can't find anywhere talking about it. I have this method getCategory that uses Apollo to query our graphQL API. The logic looks like this:

    import { useQuery, useResult } from "@vue/apollo-composable";
    import * as getCategoryBySlug from "@graphql/api/query.category.gql";

    export function useGetCategory(slug: string) {
      const { result, loading, error } = useQuery(getCategoryBySlug, { slug });
      const category = useResult(result, null, (data) => data.categoryBySlug);
      return { category, loading, error };
    }

When I want to use this in a component, I can simply do this:

    import { computed, defineComponent } from "@vue/composition-api";

    import { useGetCategory } from "@logic/get-category";
    import CategoryTitle from "@components/category-title/category-title.component.vue";
    import Products from "@components/products/products.component.vue";

    import { defineComponent } from "@vue/composition-api";

    import { useGetCategory } from "@logic/get-category";
    import CategoryTitle from "@components/category-title/category-title.component.vue";
    import Products from "@components/products/products.component.vue";

    export default defineComponent({
      name: "Categories",
      components: { CategoryTitle, Products },
      setup(_, context) {
        const { category, loading, error } = useGetCategory(
          context.root.$route.params.slug
        );

        return { category, loading, error };
      },
    });

And that's fine. Then in my template, I can do what I need to do like this:

    <template>
      <div>
        <category-title v-if="category" :category="category"> </category-title>
        <base-loader :loading="loading"> </base-loader>
        <products :category="category" v-if="category"></products>
      </div>
    </template>

    <script src="./category.component.ts" lang="ts"></script>
    <style src="./category.component.scss" lang="scss" scoped></style>

Now comes the issue (which in my mind, should be dead easy). I need to handle route changes, specifically the slug. So I have changed my code to this:

    import { computed, defineComponent } from "@vue/composition-api";

    import { useGetCategory } from "@logic/get-category";
    import CategoryTitle from "@components/category-title/category-title.component.vue";
    import Products from "@components/products/products.component.vue";

    export default defineComponent({
      name: "Categories",
      components: { CategoryTitle, Products },
      setup(_, context) {
        const result = computed(() => {
          return useGetCategory(context.root.$route.params.slug);
        });

        return { result };
      },
    });

which means I have to update my template to this:

    <template>
      <div v-if="result">
        <category-title
          v-if="result.category.value"
          :category="result.category.value"
        >
        </category-title>
        <base-loader :loading="result.loading.value"> </base-loader>
        <products
          :category="result.category.value"
          v-if="result.category.value"
        ></products>
      </div>
    </template>

    <script src="./category.component.ts" lang="ts"></script>
    <style src="./category.component.scss" lang="scss" scoped></style>

Which is just ugly. My question is this, can I destructure the computed property or something so my template can stay the same as it was?

Upvotes: 1

Views: 2453

Answers (1)

Michal Lev&#253;
Michal Lev&#253;

Reputation: 37793

You can destructure object returned by your computed but you will lose reactivity (category, loading, error variables created by destructuring computed value will not be updated when computed re-evaluates)

What you want is to use Vue Apollo ability to refresh query when it's variables change

    import { useQuery, useResult } from "@vue/apollo-composable";
    import * as getCategoryBySlug from "@graphql/api/query.category.gql";

    export function useGetCategory(params) {
      const { result, loading, error } = useQuery(getCategoryBySlug, params);
      const category = useResult(result, null, (data) => data.categoryBySlug);
      return { category, loading, error };
    }

in component...

    import { computed, defineComponent } from "@vue/composition-api";

    import { useGetCategory } from "@logic/get-category";
    import CategoryTitle from "@components/category-title/category-title.component.vue";
    import Products from "@components/products/products.component.vue";

    export default defineComponent({
      name: "Categories",
      components: { CategoryTitle, Products },
      setup(_, context) {
        const params = computed(() => 
          return {
             slug: context.root.$route.params.slug
          }
        ) 
       
        const { category, loading, error } = useGetCategory(params);
      },
    });

Upvotes: 2

Related Questions