Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit dabb397

Browse files
committed
fix(runtime-core): fix effectscope instance null
1 parent 020851e commit dabb397

File tree

2 files changed

+94
-19
lines changed

2 files changed

+94
-19
lines changed

‎packages/runtime-core/__tests__/apiWatch.spec.ts‎

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import {
88
defineComponent,
99
getCurrentInstance,
1010
ComponentInternalInstance,
11-
ComponentPublicInstance
11+
ComponentPublicInstance,
12+
onErrorCaptured
1213
} from '../src/index'
1314
import {
1415
render,
@@ -1205,4 +1206,62 @@ describe('api: watch', () => {
12051206
expect(countWE).toBe(3)
12061207
expect(countW).toBe(2)
12071208
})
1209+
1210+
test('watch immediate error in effect scope should be catched by onErrorCaptured', async () => {
1211+
const warn = vi.spyOn(console, 'warn')
1212+
warn.mockImplementation(() => {})
1213+
const ERROR_IN_SCOPE = 'ERROR_IN_SCOPE'
1214+
const ERROR_OUT_SCOPE = 'ERROR_OUT_SCOPE'
1215+
1216+
const errors = ref<string[]>([])
1217+
const Comp = {
1218+
setup() {
1219+
const trigger = ref(0)
1220+
1221+
effectScope(true).run(() => {
1222+
watch(
1223+
trigger,
1224+
() => {
1225+
throw new Error(ERROR_IN_SCOPE)
1226+
},
1227+
{ immediate: true }
1228+
)
1229+
})
1230+
1231+
watchEffect(() => {
1232+
throw new Error(ERROR_OUT_SCOPE)
1233+
})
1234+
1235+
return () => ''
1236+
}
1237+
}
1238+
1239+
// const ErrorCapture =
1240+
1241+
const root = nodeOps.createElement('div')
1242+
render(
1243+
h(
1244+
{
1245+
setup(_, { slots }) {
1246+
onErrorCaptured(e => {
1247+
errors.value.push(e.message)
1248+
return false
1249+
})
1250+
1251+
return () => h('div', slots.default && slots.default())
1252+
}
1253+
},
1254+
null,
1255+
() => [h(Comp)]
1256+
),
1257+
root
1258+
)
1259+
await nextTick()
1260+
// only watchEffect as ran so far
1261+
expect(errors.value).toHaveLength(2)
1262+
expect(errors.value[0]).toBe(ERROR_IN_SCOPE)
1263+
expect(errors.value[1]).toBe(ERROR_OUT_SCOPE)
1264+
1265+
warn.mockRestore()
1266+
})
12081267
})

‎packages/runtime-core/src/apiWatch.ts‎

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,8 @@ function doWatch(
200200

201201
const instance =
202202
getCurrentScope() === currentInstance?.scope ? currentInstance : null
203+
const detachedInstance = () =>
204+
!currentInstance || currentInstance?.isUnmounted ? null : currentInstance
203205
// const instance = currentInstance
204206
let getter: () => any
205207
let forceTrigger = false
@@ -230,7 +232,11 @@ function doWatch(
230232
if (cb) {
231233
// getter with cb
232234
getter = () =>
233-
callWithErrorHandling(source, instance, ErrorCodes.WATCH_GETTER)
235+
callWithErrorHandling(
236+
source,
237+
instance || detachedInstance(),
238+
ErrorCodes.WATCH_GETTER
239+
)
234240
} else {
235241
// no cb -> simple effect
236242
getter = () => {
@@ -242,7 +248,7 @@ function doWatch(
242248
}
243249
return callWithAsyncErrorHandling(
244250
source,
245-
instance,
251+
instance || detachedInstance(),
246252
ErrorCodes.WATCH_CALLBACK,
247253
[onCleanup]
248254
)
@@ -276,7 +282,11 @@ function doWatch(
276282
let cleanup: () => void
277283
let onCleanup: OnCleanup = (fn: () => void) => {
278284
cleanup = effect.onStop = () => {
279-
callWithErrorHandling(fn, instance, ErrorCodes.WATCH_CLEANUP)
285+
callWithErrorHandling(
286+
fn,
287+
instance || detachedInstance(),
288+
ErrorCodes.WATCH_CLEANUP
289+
)
280290
}
281291
}
282292

@@ -289,11 +299,12 @@ function doWatch(
289299
if (!cb) {
290300
getter()
291301
} else if (immediate) {
292-
callWithAsyncErrorHandling(cb, instance, ErrorCodes.WATCH_CALLBACK, [
293-
getter(),
294-
isMultiSource ? [] : undefined,
295-
onCleanup
296-
])
302+
callWithAsyncErrorHandling(
303+
cb,
304+
instance || detachedInstance(),
305+
ErrorCodes.WATCH_CALLBACK,
306+
[getter(), isMultiSource ? [] : undefined, onCleanup]
307+
)
297308
}
298309
if (flush === 'sync') {
299310
const ctx = useSSRContext()!
@@ -327,16 +338,21 @@ function doWatch(
327338
if (cleanup) {
328339
cleanup()
329340
}
330-
callWithAsyncErrorHandling(cb, instance, ErrorCodes.WATCH_CALLBACK, [
331-
newValue,
332-
// pass undefined as the old value when it's changed for the first time
333-
oldValue === INITIAL_WATCHER_VALUE
334-
? undefined
335-
: isMultiSource && oldValue[0] === INITIAL_WATCHER_VALUE
336-
? []
337-
: oldValue,
338-
onCleanup
339-
])
341+
callWithAsyncErrorHandling(
342+
cb,
343+
instance || detachedInstance(),
344+
ErrorCodes.WATCH_CALLBACK,
345+
[
346+
newValue,
347+
// pass undefined as the old value when it's changed for the first time
348+
oldValue === INITIAL_WATCHER_VALUE
349+
? undefined
350+
: isMultiSource && oldValue[0] === INITIAL_WATCHER_VALUE
351+
? []
352+
: oldValue,
353+
onCleanup
354+
]
355+
)
340356
oldValue = newValue
341357
}
342358
} else {

0 commit comments

Comments
 (0)