Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Using vue-apollo-composable inside a Pinia setup store #1527

Open
bipsen opened this issue Jan 11, 2024 · 4 comments
Open

Using vue-apollo-composable inside a Pinia setup store #1527

bipsen opened this issue Jan 11, 2024 · 4 comments

Comments

@bipsen
Copy link

bipsen commented Jan 11, 2024

I expect to be able to make queries inside a pinia setup store as per #1505.

When I run the code below, however, result stays undefined. I can see from the watchEffect log that the query runs and gets the correct response, so why doesn't result seem to be reactive in my component?

// stores/campers.ts
import SOME_QUERY from "@/gql/queries/SOME_QUERY.gql";

export const useCamperStore = defineStore("campers", () => {
  const { data: authData } = useAuth();

  const camperQueryVariables = computed(() => {
    return {
      id: authData.value?.id,
    };
  });

  const { result, refetch } = useQuery(SOME_QUERY, camperQueryVariables);

  watchEffect(() => console.log(result.value));

  return {
    result,
    refetch,
    camperQueryVariables,
  };
});
//SomeComponent.ts
<template>
  <div>
    <!-- This is undefined -->
    result: {{ result }} 

    <!-- This works as expected -->
    camperQueryVariables: {{ camperQueryVariables }}
  </div>
</template>

<script lang="ts" setup>
import { useCamperStore } from "@/stores/campers";
const { result, camperQueryVariables } = useCamperStore();
</script>

Versions
"vue": "^3.3.4",
"nuxt": "^3.7.4",
"@nuxtjs/apollo": "^5.0.0-alpha.7",
"@vue/apollo-composable": "^4.0.0-beta.11",
"@apollo/client": "^3.8.7",

@bipsen
Copy link
Author

bipsen commented Jan 11, 2024

My best solution so far has been to use a reactive object with onResult. Is that best solution to this problem?

// stores/campers.ts
import SOME_QUERY from "@/gql/queries/SOME_QUERY.gql";

export const useCamperStore = defineStore("campers", () => {
  const result = reactive({ data: null });

  const { data: authData } = useAuth();

  const camperQueryVariables = computed(() => {
    return {
      id: authData.value?.id,
    };
  });

  const { onResult, refetch } = useQuery(SOME_QUERY, camperQueryVariables);

  onResult((queryResult) => {
    result.data = queryResult.data;
  });

  return {
    result,
    refetch,
  };
});

@Akryum
Copy link
Member

Akryum commented Jan 15, 2024

See a working example here that is passing in our automated tests.

@dash-
Copy link

dash- commented Aug 12, 2024

I don't have issues with simple implementations like what is passing in that automated test. I do run into issues when there is one or more query variable that changes, particularly when paired with vue-router navigations.

@keithmifsud
Copy link

💡 I found that using Vue Apollo in Pinia - options method causes memory leaks and as of recent; produces this error:

#1568

The error occurs when triggering a query requiring a variable from another query. To solve this, I updated the stores to use the setup method and also tell VueApollo which apolloClient to use.

Example (truncated:

Pinia store

import { apolloClient, uploadClient } from '@/graphql/apolloClient.js'
import { defineStore } from 'pinia'
import { reactive, ref } from 'vue'
import { GET_CLIENT_TYPE_AVAILABLE_FIELDS_QUERY } from '@/graphql/queries/clients/getClientTypeAvailableFields.js'
import { useUserStore } from '@/stores/user.js'
import { LIST_AVAILABLE_CLIENT_TYPES_QUERY } from '@/graphql/queries/clients/listAvailableClientTypes.js'

export const useClientsStore = defineStore(
  'clients-store', () => {
    const currentClientAvailableFields = ref(null)
    const loadingCurrentClientAvailableFields = ref(true)
    const availableClientTypes = ref(null)
    const loadingAvailableClientTypes = ref(true)

    const userStore = useUserStore()

    function $reset () {
      currentClientAvailableFields.value = null
      loadingCurrentClientAvailableFields.value = true
      availableClientTypes.value = null
      loadingAvailableClientTypes.value = true
    }

    /**
     * Retrieves the available fields for a client type.
     * @param {String} clientTypeIdentifier
     * @returns {Promise<unknown>}
     */
    async function retrieveAvailableFieldsForClientType (
      clientTypeIdentifier
    ) {

      return await new Promise((resolve, reject) => {
        loadingCurrentClientAvailableFields.value = true

        apolloClient.query({
          query: GET_CLIENT_TYPE_AVAILABLE_FIELDS_QUERY,
          variables: {
            clientTypeIdentifier: clientTypeIdentifier,
            companyIdentifier: userStore.getCurrentCompany.identifier
          },
          fetchPolicy: 'network-only',
        }).then((result) => {
          currentClientAvailableFields.value = result.data.getClientTypeAvailableFields
          loadingCurrentClientAvailableFields.value = false
          resolve(currentClientAvailableFields.value)
        }).catch((error) => {
          loadingCurrentClientAvailableFields.value = false
          reject(error)
        })
      })
    }


    /**
     * Retrieves the available client types
     * @returns {Promise<unknown>}
     */
    async function retrieveAvailableClientTypes () {
      return await new Promise((resolve, reject) => {
        loadingAvailableClientTypes.value = true

        apolloClient.query({
          query: LIST_AVAILABLE_CLIENT_TYPES_QUERY,
          variables: {
            companyIdentifier: userStore.getCurrentCompany.identifier
          },
          fetchPolicy: 'network-only',
        }).then((result) => {
          availableClientTypes.value = result.data.listAvailableClientTypes
          loadingAvailableClientTypes.value = false
          resolve(availableClientTypes.value)
        }).catch((error) => {
          loadingAvailableClientTypes.value = false
          reject(error)
        })

      })
    }

    return {
      currentClient,
      loadingCurrentClient,
      currentClientAvailableFields,
      loadingCurrentClientAvailableFields,
      availableClientTypes,
      loadingAvailableClientTypes,
      $reset,
      retrieveAvailableFieldsForClientType,
      retrieveAvailableClientTypes,
    }
  },
  {
    persist: {
      enabled: true,
      strategies: [
        {
          key: 'clients-store',
          storage: localStorage,
        }
      ],
    }
  }
)

Usage:

onBeforeMount(async () => {
  await retrieveFieldsForClientType()
})

async function retrieveFieldsForClientType (clientTypeIdentifier = null) {
  if (!clientTypeIdentifier) {
    clientTypeIdentifier = defaultClientType.value?.value
  }

  await clientsStore.retrieveAvailableFieldsForClientType(
      clientTypeIdentifier
  )
}

async function changeClientType (clientTypeIdentifier) {
  formInputs.clientTypeIdentifier = clientTypeIdentifier
  await retrieveFieldsForClientType(clientTypeIdentifier)
}

const defaultClientType = computed(() => {
  return clientTypes.value?.find(
      type => type.label === 'Limited Company'
  )
})

const clientTypes = computed(() => {
  const availableClientTypes = clientsStore.availableClientTypes
  const types = []

  availableClientTypes?.forEach(type => {
    types.push({
      label: type.name,
      value: type.identifier,
    })
  })

  return types
})

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants