1
1
import {
2
- type BaseWatchErrorCodes ,
2
+ BaseWatchErrorCodes ,
3
3
type BaseWatchOptions ,
4
4
baseWatch ,
5
5
getCurrentScope ,
6
6
} from '@vue/reactivity'
7
- import { NOOP , remove } from '@vue/shared'
7
+ import { NOOP , invokeArrayFns , remove } from '@vue/shared'
8
8
import { currentInstance } from './component'
9
- import { createVaporRenderingScheduler } from './scheduler'
10
- import { handleError as handleErrorWithInstance } from './errorHandling'
9
+ import {
10
+ createVaporRenderingScheduler ,
11
+ queuePostRenderEffect ,
12
+ } from './scheduler'
13
+ import {
14
+ callWithAsyncErrorHandling ,
15
+ handleError as handleErrorWithInstance ,
16
+ } from './errorHandling'
11
17
import { warn } from './warning'
18
+ import { invokeDirectiveHook } from './directive'
12
19
13
20
type WatchStopHandle = ( ) => void
14
21
@@ -33,11 +40,31 @@ function doWatch(source: any, cb?: any): WatchStopHandle {
33
40
// TODO: SSR
34
41
// if (__SSR__) {}
35
42
43
+ if ( __DEV__ && ! currentInstance ) {
44
+ warn (
45
+ `${ cb ? 'renderWatch' : 'renderEffect' } ()` +
46
+ ' is an internal API and it can only be used inside render()' ,
47
+ )
48
+ }
49
+
50
+ if ( cb ) {
51
+ // watch
52
+ cb = wrapEffectCallback ( cb )
53
+ } else {
54
+ // effect
55
+ source = wrapEffectCallback ( source )
56
+ }
57
+
36
58
const instance =
37
59
getCurrentScope ( ) === currentInstance ?. scope ? currentInstance : null
38
60
39
- extendOptions . onError = ( err : unknown , type : BaseWatchErrorCodes ) =>
61
+ extendOptions . onError = ( err : unknown , type : BaseWatchErrorCodes ) => {
62
+ // callback error handling is in wrapEffectCallback
63
+ if ( type === BaseWatchErrorCodes . WATCH_CALLBACK ) {
64
+ throw err
65
+ }
40
66
handleErrorWithInstance ( err , instance , type )
67
+ }
41
68
extendOptions . scheduler = createVaporRenderingScheduler ( instance )
42
69
43
70
let effect = baseWatch ( source , cb , extendOptions )
@@ -53,3 +80,55 @@ function doWatch(source: any, cb?: any): WatchStopHandle {
53
80
54
81
return unwatch
55
82
}
83
+
84
+ function wrapEffectCallback ( callback : ( ...args : any [ ] ) => any ) : Function {
85
+ const instance = currentInstance !
86
+
87
+ return ( ...args : any [ ] ) => {
88
+ // with lifecycle
89
+ if ( instance . isMounted ) {
90
+ const { bu, u, dirs } = instance
91
+ // currentInstance.updating = true
92
+ // beforeUpdate hook
93
+ const isFirstEffect = ! instance . isUpdating
94
+ if ( isFirstEffect ) {
95
+ if ( bu ) {
96
+ invokeArrayFns ( bu )
97
+ }
98
+ if ( dirs ) {
99
+ invokeDirectiveHook ( instance , 'beforeUpdate' )
100
+ }
101
+ instance . isUpdating = true
102
+ }
103
+
104
+ // run callback
105
+ callWithAsyncErrorHandling (
106
+ callback ,
107
+ instance ,
108
+ BaseWatchErrorCodes . WATCH_CALLBACK ,
109
+ args ,
110
+ )
111
+
112
+ if ( isFirstEffect ) {
113
+ if ( dirs ) {
114
+ queuePostRenderEffect ( ( ) => {
115
+ instance . isUpdating = false
116
+ invokeDirectiveHook ( instance , 'updated' )
117
+ } )
118
+ }
119
+ // updated hook
120
+ if ( u ) {
121
+ queuePostRenderEffect ( u )
122
+ }
123
+ }
124
+ } else {
125
+ // is not mounted
126
+ callWithAsyncErrorHandling (
127
+ callback ,
128
+ instance ,
129
+ BaseWatchErrorCodes . WATCH_CALLBACK ,
130
+ args ,
131
+ )
132
+ }
133
+ }
134
+ }
0 commit comments