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'
24import {
35 type DebuggerEvent ,
46 type DebuggerOptions ,
5- EffectFlags ,
6- type Subscriber ,
77 activeSub ,
8- batch ,
9- refreshComputed ,
8+ activeTrackId ,
9+ nextTrackId ,
10+ setActiveSub ,
1011} from './effect'
12+ import { activeEffectScope } from './effectScope'
1113import 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'
1224import { warn } from './warning'
13- import { Dep , type Link , globalVersion } from './dep'
14- import { ReactiveFlags , TrackOpTypes } from './constants'
1525
1626declare const ComputedRefSymbol : unique symbol
1727declare const WritableComputedRefSymbol : unique symbol
@@ -44,15 +54,23 @@ export interface WritableComputedOptions<T, S = T> {
4454 * @private exported by @vue/reactivity for Vue core use, but not exported from
4555 * the main vue package
4656 */
47- export class ComputedRefImpl < T = any > implements Subscriber {
57+ export class ComputedRefImpl < T = any > implements IComputed {
4858 /**
4959 * @internal
5060 */
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+
5674 /**
5775 * @internal
5876 */
@@ -63,34 +81,39 @@ export class ComputedRefImpl<T = any> implements Subscriber {
6381 */
6482 readonly __v_isReadonly : boolean
6583 // 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
9184
9285 // 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+
94117 // dev only
95118 onTrack ?: ( event : DebuggerEvent ) => void
96119 // dev only
@@ -105,43 +128,34 @@ export class ComputedRefImpl<T = any> implements Subscriber {
105128 constructor (
106129 public fn : ComputedGetter < T > ,
107130 private readonly setter : ComputedSetter < T > | undefined ,
108- isSSR : boolean ,
109131 ) {
110132 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 )
128135 }
129136 }
130137
131138 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 ! , {
134145 target : this ,
135146 type : TrackOpTypes . GET ,
136147 key : 'value' ,
137148 } )
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 )
143157 }
144- return this . _value
158+ return this . _value !
145159 }
146160
147161 set value ( newValue ) {
@@ -151,6 +165,27 @@ export class ComputedRefImpl<T = any> implements Subscriber {
151165 warn ( 'Write operation failed: computed value is readonly' )
152166 }
153167 }
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+ }
154189}
155190
156191/**
@@ -209,7 +244,7 @@ export function computed<T>(
209244 setter = getterOrOptions . set
210245 }
211246
212- const cRef = new ComputedRefImpl ( getter , setter , isSSR )
247+ const cRef = new ComputedRefImpl ( getter , setter )
213248
214249 if ( __DEV__ && debugOptions && ! isSSR ) {
215250 cRef . onTrack = debugOptions . onTrack
0 commit comments