Просмотр исходного кода

fix(reactivity): preserve watch callback return value when wrapped for `once: true` (#14902)

Saxon Landers 2 дней назад
Родитель
Сommit
450a8a8e45
2 измененных файлов с 43 добавлено и 1 удалено
  1. 41 0
      packages/reactivity/__tests__/watch.spec.ts
  2. 2 1
      packages/reactivity/src/watch.ts

+ 41 - 0
packages/reactivity/__tests__/watch.spec.ts

@@ -116,6 +116,47 @@ describe('watch', () => {
     ])
   })
 
+  test('call option with async error handling', async () => {
+    const onError = vi.fn()
+    const call: WatchOptions['call'] = function call(fn, type, args) {
+      if (Array.isArray(fn)) {
+        fn.forEach(f => call(f, type, args))
+        return
+      }
+      fn.apply(null, args).catch((error: unknown) => {
+        onError(error)
+      })
+    }
+
+    const source1 = ref(0)
+    watch(
+      source1,
+      async () => {
+        throw 'oops in watch'
+      },
+      { call },
+    )
+
+    source1.value++
+    await nextTick()
+    expect(onError.mock.calls.length).toBe(1)
+    expect(onError.mock.calls[0]).toMatchObject(['oops in watch'])
+
+    const source2 = ref(0)
+    watch(
+      source2,
+      async () => {
+        throw 'oops in once watch'
+      },
+      { call, once: true },
+    )
+
+    source2.value++
+    await nextTick()
+    expect(onError.mock.calls.length).toBe(2)
+    expect(onError.mock.calls[1]).toMatchObject(['oops in once watch'])
+  })
+
   test('watch with onWatcherCleanup', async () => {
     let dummy = 0
     let source: Ref<number>

+ 2 - 1
packages/reactivity/src/watch.ts

@@ -221,8 +221,9 @@ export function watch(
   if (once && cb) {
     const _cb = cb
     cb = (...args) => {
-      _cb(...args)
+      const res = _cb(...args)
       watchHandle()
+      return res
     }
   }