Skip to content

Commit 6fa46ab

Browse files
authored
fix: change teardown to use onScopeDispose (#1545)
1 parent dbd1c8d commit 6fa46ab

File tree

8 files changed

+80
-40
lines changed

8 files changed

+80
-40
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<script lang="ts" setup>
2+
import { ref } from 'vue'
3+
4+
import ChannelListPinia from './ChannelListPinia.vue'
5+
6+
const isComponentVisible = ref(true)
7+
</script>
8+
9+
<template>
10+
<div>
11+
<button
12+
data-test-id="channel-list-toggle"
13+
@click="isComponentVisible = !isComponentVisible"
14+
>
15+
Toggle ChannelListPinia component
16+
</button>
17+
18+
<div
19+
v-if="isComponentVisible"
20+
data-test-id="channel-list-container"
21+
>
22+
<ChannelListPinia />
23+
</div>
24+
</div>
25+
</template>

packages/test-e2e-composable-vue3/src/router.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,13 @@ export const router = createRouter({
7272
layout: 'blank',
7373
},
7474
},
75+
{
76+
path: '/pinia3',
77+
component: () => import('./components/ChannelListPiniaContainer.vue'),
78+
meta: {
79+
layout: 'blank',
80+
},
81+
},
7582
{
7683
path: '/no-setup-scope-query',
7784
component: () => import('./components/NoSetupScopeQuery.vue'),

packages/test-e2e-composable-vue3/tests/e2e/specs/pinia.cy.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,15 @@ describe('Pinia', () => {
1616
cy.contains('.channel-link', '# General')
1717
cy.contains('.channel-link', '# Random')
1818
})
19+
20+
it('works after component unmount if used in pinia', () => {
21+
cy.visit('/pinia3')
22+
cy.get('[data-test-id="channel-list-container"]').should('exist')
23+
cy.get('[data-test-id="channel-list-toggle"]').first().click()
24+
cy.get('[data-test-id="channel-list-container"]').should('not.exist')
25+
cy.get('[data-test-id="channel-list-toggle"]').first().click()
26+
cy.get('.channel-link').should('have.lengthOf', 2)
27+
cy.contains('.channel-link', '# General')
28+
cy.contains('.channel-link', '# Random')
29+
})
1930
})

packages/vue-apollo-composable/src/useMutation.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { DocumentNode } from 'graphql'
22
import { MutationOptions, OperationVariables, FetchResult, TypedDocumentNode, ApolloError, ApolloClient } from '@apollo/client/core/index.js'
3-
import { ref, onBeforeUnmount, isRef, Ref, getCurrentInstance, shallowRef } from 'vue-demi'
3+
import { ref, onScopeDispose, isRef, Ref, getCurrentScope, shallowRef } from 'vue-demi'
44
import { useApolloClient } from './useApolloClient'
55
import { ReactiveFunction } from './util/ReactiveFunction'
66
import { useEventHook } from './util/useEventHook'
@@ -53,9 +53,9 @@ export function useMutation<
5353
document: DocumentParameter<TResult, TVariables>,
5454
options: OptionsParameter<TResult, TVariables> = {},
5555
): UseMutationReturn<TResult, TVariables> {
56-
const vm = getCurrentInstance()
56+
const currentScope = getCurrentScope()
5757
const loading = ref<boolean>(false)
58-
vm && trackMutation(loading)
58+
currentScope && trackMutation(loading)
5959
const error = shallowRef<ApolloError | null>(null)
6060
const called = ref<boolean>(false)
6161

@@ -118,7 +118,7 @@ export function useMutation<
118118
return null
119119
}
120120

121-
vm && onBeforeUnmount(() => {
121+
currentScope && onScopeDispose(() => {
122122
loading.value = false
123123
})
124124

packages/vue-apollo-composable/src/useQuery.ts

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import {
55
computed,
66
watch,
77
onServerPrefetch,
8-
getCurrentInstance,
9-
onBeforeUnmount,
8+
getCurrentScope,
9+
onScopeDispose,
1010
nextTick,
1111
shallowRef,
1212
} from 'vue-demi'
@@ -34,8 +34,6 @@ import { trackQuery } from './util/loadingTracking'
3434
import { resultErrorsToApolloError, toApolloError } from './util/toApolloError'
3535
import { isServer } from './util/env'
3636

37-
import type { CurrentInstance } from './util/types'
38-
3937
export interface UseQueryOptions<
4038
// eslint-disable-next-line @typescript-eslint/no-unused-vars
4139
TResult = any,
@@ -152,8 +150,7 @@ export function useQueryImpl<
152150
options: OptionsParameter<TResult, TVariables> = {},
153151
lazy = false,
154152
): UseQueryReturn<TResult, TVariables> {
155-
// Is on server?
156-
const vm = getCurrentInstance() as CurrentInstance | null
153+
const currentScope = getCurrentScope()
157154

158155
const currentOptions = ref<UseQueryOptions<TResult, TVariables>>()
159156

@@ -176,7 +173,7 @@ export function useQueryImpl<
176173
* Indicates if a network request is pending
177174
*/
178175
const loading = ref(false)
179-
vm && trackQuery(loading)
176+
currentScope && trackQuery(loading)
180177
const networkStatus = ref<number>()
181178

182179
// SSR
@@ -202,7 +199,7 @@ export function useQueryImpl<
202199
firstRejectError = undefined
203200
}
204201

205-
vm && onServerPrefetch?.(() => {
202+
currentScope && onServerPrefetch?.(() => {
206203
if (!isEnabled.value || (isServer && currentOptions.value?.prefetch === false)) return
207204

208205
return new Promise<void>((resolve, reject) => {
@@ -615,10 +612,14 @@ export function useQueryImpl<
615612
}
616613

617614
// Teardown
618-
vm && onBeforeUnmount(() => {
619-
stop()
620-
subscribeToMoreItems.length = 0
621-
})
615+
if (currentScope) {
616+
onScopeDispose(() => {
617+
stop()
618+
subscribeToMoreItems.length = 0
619+
})
620+
} else {
621+
console.warn('[Vue apollo] useQuery() is called outside of an active effect scope and the query will not be automatically stopped.')
622+
}
622623

623624
return {
624625
result,

packages/vue-apollo-composable/src/useSubscription.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import {
55
watch,
66
isRef,
77
computed,
8-
getCurrentInstance,
9-
onBeforeUnmount,
8+
getCurrentScope,
9+
onScopeDispose,
1010
nextTick,
1111
shallowRef,
1212
} from 'vue-demi'
@@ -27,7 +27,6 @@ import { paramToReactive } from './util/paramToReactive'
2727
import { useApolloClient } from './useApolloClient'
2828
import { useEventHook } from './util/useEventHook'
2929
import { trackSubscription } from './util/loadingTracking'
30-
import type { CurrentInstance } from './util/types'
3130
import { toApolloError } from './util/toApolloError'
3231
import { isServer } from './util/env'
3332

@@ -121,8 +120,7 @@ export function useSubscription <
121120
variables: VariablesParameter<TVariables> | undefined = undefined,
122121
options: OptionsParameter<TResult, TVariables> = {},
123122
): UseSubscriptionReturn<TResult, TVariables> {
124-
// Is on server?
125-
const vm = getCurrentInstance() as CurrentInstance | null
123+
const currentScope = getCurrentScope()
126124

127125
const documentRef = paramToRef(document)
128126
const variablesRef = paramToRef(variables)
@@ -134,7 +132,7 @@ export function useSubscription <
134132
const errorEvent = useEventHook<[ApolloError, OnErrorContext]>()
135133

136134
const loading = ref(false)
137-
vm && trackSubscription(loading)
135+
currentScope && trackSubscription(loading)
138136

139137
// Apollo Client
140138
const { resolveClient } = useApolloClient()
@@ -298,7 +296,11 @@ export function useSubscription <
298296
})
299297

300298
// Teardown
301-
vm && onBeforeUnmount(stop)
299+
if (currentScope) {
300+
onScopeDispose(stop)
301+
} else {
302+
console.warn('[Vue apollo] useSubscription() is called outside of an active effect scope and the subscription will not be automatically stopped.')
303+
}
302304

303305
return {
304306
result,

packages/vue-apollo-composable/src/util/loadingTracking.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
1-
import { Ref, watch, onUnmounted, ref, getCurrentInstance, onBeforeUnmount } from 'vue-demi'
1+
import { Ref, watch, onUnmounted, ref, getCurrentScope, onScopeDispose } from 'vue-demi'
22
import { isServer } from './env.js'
33

4+
import type { EffectScope } from 'vue-demi'
5+
46
export interface LoadingTracking {
57
queries: Ref<number>
68
mutations: Ref<number>
79
subscriptions: Ref<number>
810
}
911

1012
export interface AppLoadingTracking extends LoadingTracking {
11-
components: Map<any, LoadingTracking>
13+
components: Map<EffectScope, LoadingTracking>
1214
}
1315

1416
export const globalTracking: AppLoadingTracking = {
@@ -19,26 +21,26 @@ export const globalTracking: AppLoadingTracking = {
1921
}
2022

2123
export function getCurrentTracking () {
22-
const vm = getCurrentInstance()
23-
if (!vm) {
24+
const currentScope = getCurrentScope()
25+
if (!currentScope) {
2426
return {}
2527
}
2628

2729
let tracking: LoadingTracking
2830

29-
if (!globalTracking.components.has(vm)) {
31+
if (!globalTracking.components.has(currentScope)) {
3032
// Add per-component tracking
31-
globalTracking.components.set(vm, tracking = {
33+
globalTracking.components.set(currentScope, tracking = {
3234
queries: ref(0),
3335
mutations: ref(0),
3436
subscriptions: ref(0),
3537
})
3638
// Cleanup
3739
onUnmounted(() => {
38-
globalTracking.components.delete(vm)
40+
globalTracking.components.delete(currentScope)
3941
})
4042
} else {
41-
tracking = globalTracking.components.get(vm) as LoadingTracking
43+
tracking = globalTracking.components.get(currentScope) as LoadingTracking
4244
}
4345

4446
return {
@@ -61,7 +63,7 @@ function track (loading: Ref<boolean>, type: keyof LoadingTracking) {
6163
immediate: true,
6264
})
6365

64-
onBeforeUnmount(() => {
66+
onScopeDispose(() => {
6567
if (loading.value) {
6668
if (tracking) tracking[type].value--
6769
globalTracking[type].value--

packages/vue-apollo-composable/src/util/types.ts

Lines changed: 0 additions & 8 deletions
This file was deleted.

0 commit comments

Comments
 (0)