feat: allow providing multiple apolloClients outside of setup/vue context in vue-apollo-composable (#1340)

* allow providing multiple apolloClients outside of setup/vue context

* add docs

Co-authored-by: Rico Schmidt <schmidt@joshmartin.ch>
This commit is contained in:
Leo Zurbriggen
2022-05-03 10:43:12 +02:00
committed by GitHub
parent 61261bccc4
commit 64491ce1ca
6 changed files with 106 additions and 11 deletions
@@ -82,3 +82,27 @@ provide(ApolloClients, {
```
You can then select which one to use in functions we will cover next (such as `useQuery`, `useMutation` and `useSubscription`) with the `clientId` option.
## Usage outside of setup
When using e.g. `useQuery` outside of vue contexts, the clients cannot be injected using vue's provide/inject mechanism. `@vue/apollo-composable` can manage their own apollo clients
Use `provideApolloClient` for a single default client:
```js
import { provideApolloClient } from "@vue/apollo-composable";
provideApolloClient(apolloClient)
```
Use `provideApolloClients` for multiple clients:
```js
import { provideApolloClients } from "@vue/apollo-composable";
provideApolloClients({
default: apolloClient,
clientA: apolloClientA,
clientB: apolloClientB,
})
```
@@ -0,0 +1,35 @@
<script lang="ts">
import { apolloClient } from '@/apollo'
import gql from 'graphql-tag'
import { useQuery, useResult, provideApolloClients } from '@vue/apollo-composable'
import { defineComponent } from 'vue'
// Global query
const query = provideApolloClients({ myCustomClientId: apolloClient })(() =>
useQuery(
gql`
query hello {
hello
}
`,
{},
{ clientId: 'myCustomClientId' },
),
)
const hello = useResult(query.result, [])
export default defineComponent({
setup () {
return {
hello,
}
},
})
</script>
<template>
<div class="no-setup-query">
{{ hello }}
</div>
</template>
@@ -18,6 +18,10 @@ export const router = createRouter({
path: '/no-setup-query',
component: () => import('./components/NoSetupQuery.vue'),
},
{
path: '/no-setup-query-multi-client',
component: () => import('./components/NoSetupQueryMultiClient.vue'),
},
{
path: '/lazy-query',
component: () => import('./components/LazyQuery.vue'),
@@ -81,6 +81,11 @@ describe('Vue 3 + Apollo Composable', () => {
cy.contains('.no-setup-query', 'Hello world!')
})
it('supports queries outside of setup with multiple clients', () => {
cy.visit('/no-setup-query-multi-client')
cy.contains('.no-setup-query', 'Hello world!')
})
it('useLazyQuery', () => {
cy.visit('/lazy-query')
cy.get('.list-disc').should('have.length', 0)
@@ -43,4 +43,5 @@ export {
useApolloClient,
UseApolloClientReturn,
provideApolloClient,
provideApolloClients,
} from './useApolloClient'
@@ -33,28 +33,43 @@ export function useApolloClient<TCacheShape = any> (clientId?: ClientId): UseApo
let resolveImpl: ResolveClient<TCacheShape, NullableApolloClient<TCacheShape>>
// Save current client in current closure scope
const savedCurrentClient = currentApolloClient
const savedCurrentClients = currentApolloClients
if (!getCurrentInstance()) {
resolveImpl = () => savedCurrentClient
resolveImpl = (id?: ClientId) => {
if (id) {
return resolveClientWithId(savedCurrentClients, id)
}
return resolveDefaultClient(savedCurrentClients, savedCurrentClients.default)
}
} else {
const providedApolloClients: ClientDict<TCacheShape> | null = inject(ApolloClients, null)
const providedApolloClient: ApolloClient<TCacheShape> | null = inject(DefaultApolloClient, null)
resolveImpl = (id?: ClientId) => {
if (savedCurrentClient) {
return savedCurrentClient
} else if (id) {
return resolveClientWithId(providedApolloClients, id)
if (id) {
const client = resolveClientWithId(providedApolloClients, id)
if (client) {
return client
}
return resolveClientWithId(savedCurrentClients, id)
}
return resolveDefaultClient(providedApolloClients, providedApolloClient)
const client = resolveDefaultClient(providedApolloClients, providedApolloClient)
if (client) {
return client
}
return resolveDefaultClient(savedCurrentClients, savedCurrentClients.default)
}
}
function resolveClient (id: ClientId | undefined = clientId) {
const client = resolveImpl(id)
if (!client) {
throw new Error(`Apollo client with id ${id ?? 'default'} not found. Use provideApolloClient() if you are outside of a component setup.`)
throw new Error(
`Apollo client with id ${
id ?? 'default'
} not found. Use provideApolloClient() if you are outside of a component setup.`,
)
}
return client
}
@@ -67,13 +82,24 @@ export function useApolloClient<TCacheShape = any> (clientId?: ClientId): UseApo
}
}
let currentApolloClient: NullableApolloClient<any>
let currentApolloClients: ClientDict<any> = {}
export function provideApolloClient<TCacheShape = any> (client: ApolloClient<TCacheShape>) {
currentApolloClient = client
currentApolloClients = {
default: client,
}
return function <TFnResult = any> (fn: () => TFnResult) {
const result = fn()
currentApolloClient = undefined
currentApolloClients = {}
return result
}
}
export function provideApolloClients<TCacheShape = any> (clients: ClientDict<TCacheShape>) {
currentApolloClients = clients
return function <TFnResult = any> (fn: () => TFnResult) {
const result = fn()
currentApolloClients = {}
return result
}
}