File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change 55 type WatchOptions ,
66 type WatchScheduler ,
77 computed ,
8+ effect ,
89 onWatcherCleanup ,
910 ref ,
1011 watch ,
@@ -342,4 +343,55 @@ describe('watch', () => {
342343 expect ( ( ) => ( source . value = 2 ) ) . not . toThrow ( )
343344 expect ( callback ) . toHaveBeenCalledTimes ( 1 )
344345 } )
346+
347+ // #5009
348+ test ( 'should not track deps of cleanup and callback run inside another effect' , ( ) => {
349+ const source = ref ( 0 )
350+ const dep = ref ( 0 )
351+ const cb = vi . fn ( ( ) => {
352+ dep . value
353+ onWatcherCleanup ( ( ) => dep . value )
354+ } )
355+ watch ( source , cb )
356+ source . value ++
357+ expect ( cb ) . toHaveBeenCalledTimes ( 1 )
358+
359+ const fn = vi . fn ( ( ) => {
360+ source . value = 10
361+ } )
362+ effect ( fn )
363+ expect ( cb ) . toHaveBeenCalledTimes ( 2 )
364+ expect ( fn ) . toHaveBeenCalledTimes ( 1 )
365+
366+ dep . value ++
367+ expect ( fn ) . toHaveBeenCalledTimes ( 1 )
368+ } )
369+
370+ test ( 'should restore tracking when cleanup throws inside another effect' , ( ) => {
371+ const source = ref ( 0 )
372+ const dep = ref ( 0 )
373+ const err = new Error ( 'cleanup error' )
374+ watch ( source , ( ) => {
375+ onWatcherCleanup ( ( ) => {
376+ throw err
377+ } )
378+ } )
379+ source . value ++
380+
381+ let dummy
382+ let caught
383+ effect ( ( ) => {
384+ try {
385+ source . value = 10
386+ } catch ( e ) {
387+ caught = e
388+ }
389+ dummy = dep . value
390+ } )
391+ expect ( caught ) . toBe ( err )
392+ expect ( dummy ) . toBe ( 0 )
393+
394+ dep . value ++
395+ expect ( dummy ) . toBe ( 1 )
396+ } )
345397} )
Original file line number Diff line number Diff line change @@ -251,13 +251,14 @@ export function watch(
251251 ? ( newValue as any [ ] ) . some ( ( v , i ) => hasChanged ( v , oldValue [ i ] ) )
252252 : hasChanged ( newValue , oldValue ) )
253253 ) {
254- // cleanup before running cb again
255- if ( cleanup ) {
256- cleanup ( )
257- }
258254 const currentWatcher = activeWatcher
259- activeWatcher = effect
255+ pauseTracking ( )
260256 try {
257+ // cleanup before running cb again
258+ if ( cleanup ) {
259+ cleanup ( )
260+ }
261+ activeWatcher = effect
261262 const args = [
262263 newValue ,
263264 // pass undefined as the old value when it's changed for the first time
@@ -275,6 +276,7 @@ export function watch(
275276 cb ! ( ...args )
276277 } finally {
277278 activeWatcher = currentWatcher
279+ resetTracking ( )
278280 }
279281 }
280282 } else {
Original file line number Diff line number Diff line change @@ -1424,6 +1424,47 @@ describe('api: watch', () => {
14241424 expect ( updated ) . toHaveBeenCalledTimes ( 1 )
14251425 } )
14261426
1427+ // #5009
1428+ test ( 'sync watcher callbacks should not track dependencies' , async ( ) => {
1429+ const a = ref ( 0 )
1430+ const b = ref ( 0 )
1431+ const updated = vi . fn ( )
1432+
1433+ const Child = defineComponent ( {
1434+ props : [ 'a' ] ,
1435+ updated,
1436+ watch : {
1437+ a : {
1438+ handler ( ) {
1439+ b . value
1440+ } ,
1441+ flush : 'sync' ,
1442+ } ,
1443+ } ,
1444+ render ( ) {
1445+ return h ( 'div' , this . a )
1446+ } ,
1447+ } )
1448+
1449+ const Parent = defineComponent ( {
1450+ render ( ) {
1451+ return h ( Child , { a : a . value } )
1452+ } ,
1453+ } )
1454+
1455+ const root = nodeOps . createElement ( 'div' )
1456+ createApp ( Parent ) . mount ( root )
1457+
1458+ a . value ++
1459+ await nextTick ( )
1460+ expect ( updated ) . toHaveBeenCalledTimes ( 1 )
1461+
1462+ b . value ++
1463+ await nextTick ( )
1464+ // should not track b as dependency of Child
1465+ expect ( updated ) . toHaveBeenCalledTimes ( 1 )
1466+ } )
1467+
14271468 test ( 'watching keypath' , async ( ) => {
14281469 const spy = vi . fn ( )
14291470 const Comp = defineComponent ( {
You can’t perform that action at this time.
0 commit comments