Skip to content

Commit b447ace

Browse files
authored
fix(runtime-vapor): detach effect scope & component instance (#174)
1 parent e640ec6 commit b447ace

File tree

8 files changed

+62
-13
lines changed

8 files changed

+62
-13
lines changed

packages/runtime-vapor/__tests__/dom/prop.spec.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,17 @@ import {
1414
setCurrentInstance,
1515
} from '../../src/component'
1616
import { getMetadata, recordPropMetadata } from '../../src/componentMetadata'
17+
import { getCurrentScope } from '@vue/reactivity'
1718

1819
let removeComponentInstance = NOOP
1920
beforeEach(() => {
20-
const reset = setCurrentInstance(
21-
createComponentInstance((() => {}) as any, {}),
22-
)
21+
const instance = createComponentInstance((() => {}) as any, {})
22+
const reset = setCurrentInstance(instance)
23+
const prev = getCurrentScope()
24+
instance.scope.on()
2325
removeComponentInstance = () => {
26+
instance.scope.prevScope = prev
27+
instance.scope.off()
2428
reset()
2529
removeComponentInstance = NOOP
2630
}

packages/runtime-vapor/__tests__/renderEffect.spec.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import {
2+
EffectScope,
3+
getCurrentScope,
24
nextTick,
35
onBeforeUpdate,
46
onEffectCleanup,
@@ -10,6 +12,10 @@ import {
1012
watchPostEffect,
1113
watchSyncEffect,
1214
} from '../src'
15+
import {
16+
type ComponentInternalInstance,
17+
currentInstance,
18+
} from '../src/component'
1319
import { makeRender } from './_utils'
1420

1521
const define = makeRender<any>()
@@ -207,4 +213,27 @@ describe('renderEffect', () => {
207213
'[Vue warn] Unhandled error during execution of updated',
208214
).toHaveBeenWarned()
209215
})
216+
217+
test('should be called with the current instance and current scope', async () => {
218+
const source = ref(0)
219+
const scope = new EffectScope()
220+
let instanceSnap: ComponentInternalInstance | null = null
221+
let scopeSnap: EffectScope | undefined = undefined
222+
const { instance } = define(() => {
223+
scope.run(() => {
224+
renderEffect(() => {
225+
instanceSnap = currentInstance
226+
scopeSnap = getCurrentScope()
227+
})
228+
})
229+
}).render()
230+
231+
expect(instanceSnap).toBe(instance)
232+
expect(scopeSnap).toBe(scope)
233+
234+
source.value++
235+
await nextTick()
236+
expect(instanceSnap).toBe(instance)
237+
expect(scopeSnap).toBe(scope)
238+
})
210239
})

packages/runtime-vapor/src/apiLifecycle.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ const injectHook = (
3939
}
4040
pauseTracking()
4141
const reset = setCurrentInstance(target)
42-
const res = callWithAsyncErrorHandling(hook, target, type, args)
42+
const res = target.scope.run(() =>
43+
callWithAsyncErrorHandling(hook, target, type, args),
44+
)
4345
reset()
4446
resetTracking()
4547
return res

packages/runtime-vapor/src/apiRender.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,9 @@ export function setupComponent(
6464
instance.setupState = proxyRefs(stateOrNode)
6565
}
6666
if (!block && component.render) {
67+
pauseTracking()
6768
block = component.render(instance.setupState)
69+
resetTracking()
6870
}
6971

7072
if (block instanceof DocumentFragment) {

packages/runtime-vapor/src/component.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,9 +182,7 @@ export const getCurrentInstance: () => ComponentInternalInstance | null = () =>
182182
export const setCurrentInstance = (instance: ComponentInternalInstance) => {
183183
const prev = currentInstance
184184
currentInstance = instance
185-
instance.scope.on()
186185
return () => {
187-
instance.scope.off()
188186
currentInstance = prev
189187
}
190188
}

packages/runtime-vapor/src/componentLifecycle.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export function invokeLifecycle(
1717
if (hooks) {
1818
const fn = () => {
1919
const reset = setCurrentInstance(instance)
20-
invokeArrayFns(hooks)
20+
instance.scope.run(() => invokeArrayFns(hooks))
2121
reset()
2222
}
2323
post ? queuePostRenderEffect(fn) : fn()

packages/runtime-vapor/src/componentProps.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ function resolvePropValue(
212212
// value = propsDefaults[key]
213213
// } else {
214214
const reset = setCurrentInstance(instance)
215-
value = defaultValue.call(null, props)
215+
instance.scope.run(() => (value = defaultValue.call(null, props)))
216216
reset()
217217
// }
218218
} else {

packages/runtime-vapor/src/renderEffect.ts

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
ReactiveEffect,
44
type SchedulerJob,
55
SchedulerJobFlags,
6+
getCurrentScope,
67
} from '@vue/reactivity'
78
import { invokeArrayFns } from '@vue/shared'
89
import {
@@ -16,6 +17,7 @@ import { invokeDirectiveHook } from './directives'
1617

1718
export function renderEffect(cb: () => void) {
1819
const instance = getCurrentInstance()
20+
const scope = getCurrentScope()
1921

2022
let effect: ReactiveEffect
2123

@@ -53,11 +55,23 @@ export function renderEffect(cb: () => void) {
5355
}
5456
}
5557

56-
effect = new ReactiveEffect(() => {
57-
const reset = instance && setCurrentInstance(instance)
58-
callWithAsyncErrorHandling(cb, instance, VaporErrorCodes.RENDER_FUNCTION)
59-
reset?.()
60-
})
58+
if (scope) {
59+
const baseCb = cb
60+
cb = () => scope.run(baseCb)
61+
}
62+
63+
if (instance) {
64+
const baseCb = cb
65+
cb = () => {
66+
const reset = setCurrentInstance(instance)
67+
baseCb()
68+
reset()
69+
}
70+
}
71+
72+
effect = new ReactiveEffect(() =>
73+
callWithAsyncErrorHandling(cb, instance, VaporErrorCodes.RENDER_FUNCTION),
74+
)
6175

6276
effect.scheduler = () => {
6377
if (instance) job.id = instance.uid

0 commit comments

Comments
 (0)