1
- import { isFunction } from '@vue/shared'
1
+ import { hasChanged , isFunction } from '@vue/shared'
2
+ import { ReactiveFlags , TrackOpTypes } from './constants'
3
+ import { onTrack , setupFlagsHandler } from './debug'
2
4
import {
3
5
type DebuggerEvent ,
4
6
type DebuggerOptions ,
5
- EffectFlags ,
6
- type Subscriber ,
7
7
activeSub ,
8
- batch ,
9
- refreshComputed ,
8
+ activeTrackId ,
9
+ nextTrackId ,
10
+ setActiveSub ,
10
11
} from './effect'
12
+ import { activeEffectScope } from './effectScope'
11
13
import type { Ref } from './ref'
14
+ import {
15
+ type Dependency ,
16
+ type IComputed ,
17
+ type Link ,
18
+ SubscriberFlags ,
19
+ checkDirty ,
20
+ endTrack ,
21
+ link ,
22
+ startTrack ,
23
+ } from './system'
12
24
import { warn } from './warning'
13
- import { Dep , type Link , globalVersion } from './dep'
14
- import { ReactiveFlags , TrackOpTypes } from './constants'
15
25
16
26
declare const ComputedRefSymbol : unique symbol
17
27
declare const WritableComputedRefSymbol : unique symbol
@@ -44,15 +54,23 @@ export interface WritableComputedOptions<T, S = T> {
44
54
* @private exported by @vue/reactivity for Vue core use, but not exported from
45
55
* the main vue package
46
56
*/
47
- export class ComputedRefImpl < T = any > implements Subscriber {
57
+ export class ComputedRefImpl < T = any > implements IComputed {
48
58
/**
49
59
* @internal
50
60
*/
51
- _value : any = undefined
52
- /**
53
- * @internal
54
- */
55
- readonly dep : Dep = new Dep ( this )
61
+ _value : T | undefined = undefined
62
+ version = 0
63
+
64
+ // Dependency
65
+ subs : Link | undefined = undefined
66
+ subsTail : Link | undefined = undefined
67
+ lastTrackedId = 0
68
+
69
+ // Subscriber
70
+ deps : Link | undefined = undefined
71
+ depsTail : Link | undefined = undefined
72
+ flags : SubscriberFlags = SubscriberFlags . Dirty
73
+
56
74
/**
57
75
* @internal
58
76
*/
@@ -63,34 +81,39 @@ export class ComputedRefImpl<T = any> implements Subscriber {
63
81
*/
64
82
readonly __v_isReadonly : boolean
65
83
// TODO isolatedDeclarations ReactiveFlags.IS_READONLY
66
- // A computed is also a subscriber that tracks other deps
67
- /**
68
- * @internal
69
- */
70
- deps ?: Link = undefined
71
- /**
72
- * @internal
73
- */
74
- depsTail ?: Link = undefined
75
- /**
76
- * @internal
77
- */
78
- flags : EffectFlags = EffectFlags . DIRTY
79
- /**
80
- * @internal
81
- */
82
- globalVersion : number = globalVersion - 1
83
- /**
84
- * @internal
85
- */
86
- isSSR : boolean
87
- /**
88
- * @internal
89
- */
90
- next ?: Subscriber = undefined
91
84
92
85
// for backwards compat
93
- effect : this = this
86
+ get effect ( ) : this {
87
+ return this
88
+ }
89
+ // for backwards compat
90
+ get dep ( ) : Dependency {
91
+ return this
92
+ }
93
+ // for backwards compat
94
+ get _dirty ( ) : boolean {
95
+ const flags = this . flags
96
+ if ( flags & SubscriberFlags . Dirty ) {
97
+ return true
98
+ } else if ( flags & SubscriberFlags . ToCheckDirty ) {
99
+ if ( checkDirty ( this . deps ! ) ) {
100
+ this . flags |= SubscriberFlags . Dirty
101
+ return true
102
+ } else {
103
+ this . flags &= ~ SubscriberFlags . ToCheckDirty
104
+ return false
105
+ }
106
+ }
107
+ return false
108
+ }
109
+ set _dirty ( v : boolean ) {
110
+ if ( v ) {
111
+ this . flags |= SubscriberFlags . Dirty
112
+ } else {
113
+ this . flags &= ~ SubscriberFlags . Dirtys
114
+ }
115
+ }
116
+
94
117
// dev only
95
118
onTrack ?: ( event : DebuggerEvent ) => void
96
119
// dev only
@@ -105,43 +128,34 @@ export class ComputedRefImpl<T = any> implements Subscriber {
105
128
constructor (
106
129
public fn : ComputedGetter < T > ,
107
130
private readonly setter : ComputedSetter < T > | undefined ,
108
- isSSR : boolean ,
109
131
) {
110
132
this [ ReactiveFlags . IS_READONLY ] = ! setter
111
- this . isSSR = isSSR
112
- }
113
-
114
- /**
115
- * @internal
116
- */
117
- notify ( ) : true | void {
118
- this . flags |= EffectFlags . DIRTY
119
- if (
120
- ! ( this . flags & EffectFlags . NOTIFIED ) &&
121
- // avoid infinite self recursion
122
- activeSub !== this
123
- ) {
124
- batch ( this , true )
125
- return true
126
- } else if ( __DEV__ ) {
127
- // TODO warn
133
+ if ( __DEV__ ) {
134
+ setupFlagsHandler ( this )
128
135
}
129
136
}
130
137
131
138
get value ( ) : T {
132
- const link = __DEV__
133
- ? this . dep . track ( {
139
+ if ( this . _dirty ) {
140
+ this . update ( )
141
+ }
142
+ if ( activeTrackId !== 0 && this . lastTrackedId !== activeTrackId ) {
143
+ if ( __DEV__ ) {
144
+ onTrack ( activeSub ! , {
134
145
target : this ,
135
146
type : TrackOpTypes . GET ,
136
147
key : 'value' ,
137
148
} )
138
- : this . dep . track ( )
139
- refreshComputed ( this )
140
- // sync version after evaluation
141
- if ( link ) {
142
- link . version = this . dep . version
149
+ }
150
+ this . lastTrackedId = activeTrackId
151
+ link ( this , activeSub ! ) . version = this . version
152
+ } else if (
153
+ activeEffectScope !== undefined &&
154
+ this . lastTrackedId !== activeEffectScope . trackId
155
+ ) {
156
+ link ( this , activeEffectScope )
143
157
}
144
- return this . _value
158
+ return this . _value !
145
159
}
146
160
147
161
set value ( newValue ) {
@@ -151,6 +165,27 @@ export class ComputedRefImpl<T = any> implements Subscriber {
151
165
warn ( 'Write operation failed: computed value is readonly' )
152
166
}
153
167
}
168
+
169
+ update ( ) : boolean {
170
+ const prevSub = activeSub
171
+ const prevTrackId = activeTrackId
172
+ setActiveSub ( this , nextTrackId ( ) )
173
+ startTrack ( this )
174
+ const oldValue = this . _value
175
+ let newValue : T
176
+ try {
177
+ newValue = this . fn ( oldValue )
178
+ } finally {
179
+ setActiveSub ( prevSub , prevTrackId )
180
+ endTrack ( this )
181
+ }
182
+ if ( hasChanged ( oldValue , newValue ) ) {
183
+ this . _value = newValue
184
+ this . version ++
185
+ return true
186
+ }
187
+ return false
188
+ }
154
189
}
155
190
156
191
/**
@@ -209,7 +244,7 @@ export function computed<T>(
209
244
setter = getterOrOptions . set
210
245
}
211
246
212
- const cRef = new ComputedRefImpl ( getter , setter , isSSR )
247
+ const cRef = new ComputedRefImpl ( getter , setter )
213
248
214
249
if ( __DEV__ && debugOptions && ! isSSR ) {
215
250
cRef . onTrack = debugOptions . onTrack
0 commit comments