From: Evan You Date: Mon, 26 Feb 2024 02:13:44 +0000 (+0800) Subject: chore: Merge branch 'main' into minor X-Git-Tag: v3.5.0-alpha.1~19 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=58d827cb715ea4501540c1af53aa7313000445ba;p=thirdparty%2Fvuejs%2Fcore.git chore: Merge branch 'main' into minor --- 58d827cb715ea4501540c1af53aa7313000445ba diff --cc packages/reactivity/src/collectionHandlers.ts index 2636287b61,2b7785ae7e..6f1dbd3e56 --- a/packages/reactivity/src/collectionHandlers.ts +++ b/packages/reactivity/src/collectionHandlers.ts @@@ -1,7 -1,13 +1,8 @@@ import { toRaw, toReactive, toReadonly } from './reactive' -import { - ITERATE_KEY, - MAP_KEY_ITERATE_KEY, - track, - trigger, -} from './reactiveEffect' +import { ITERATE_KEY, MAP_KEY_ITERATE_KEY, track, trigger } from './dep' import { ReactiveFlags, TrackOpTypes, TriggerOpTypes } from './constants' import { capitalize, hasChanged, hasOwn, isMap, toRawType } from '@vue/shared' + import { warn } from './warning' type CollectionTypes = IterableCollections | WeakCollections diff --cc packages/reactivity/src/computed.ts index 3e0fce6ec0,da63fe8475..a3c6de407a --- a/packages/reactivity/src/computed.ts +++ b/packages/reactivity/src/computed.ts @@@ -36,71 -25,81 +36,76 @@@ export interface WritableComputedOption set: ComputedSetter } -export const COMPUTED_SIDE_EFFECT_WARN = - `Computed is still dirty after getter evaluation,` + - ` likely because a computed is mutating its own dependency in its getter.` + - ` State mutations in computed getters should be avoided. ` + - ` Check the docs for more details: https://vuejs.org/guide/essentials/computed.html#getters-should-be-side-effect-free` - -export class ComputedRefImpl { - public dep?: Dep = undefined - - private _value!: T - public readonly effect: ReactiveEffect - - public readonly __v_isRef = true - public readonly [ReactiveFlags.IS_READONLY]: boolean = false - - public _cacheable: boolean +/** + * @internal + */ +export class ComputedRefImpl implements Subscriber { + // A computed is a ref + _value: any = undefined + readonly dep = new Dep(this) + readonly __v_isRef = true; + readonly [ReactiveFlags.IS_READONLY]: boolean + // A computed is also a subscriber that tracks other deps + deps?: Link = undefined + depsTail?: Link = undefined + // track variaous states + flags = EffectFlags.DIRTY + // last seen global version + globalVersion = globalVersion - 1 + // for backwards compat + effect = this + + // dev only + onTrack?: (event: DebuggerEvent) => void + // dev only + onTrigger?: (event: DebuggerEvent) => void + /** + * Dev only + */ + _warnRecursive?: boolean + constructor( - private getter: ComputedGetter, - private readonly _setter: ComputedSetter, - isReadonly: boolean, - isSSR: boolean, + public fn: ComputedGetter, + private readonly setter: ComputedSetter | undefined, + public isSSR: boolean, ) { - this.effect = new ReactiveEffect( - () => getter(this._value), - () => - triggerRefValue( - this, - this.effect._dirtyLevel === DirtyLevels.MaybeDirty_ComputedSideEffect - ? DirtyLevels.MaybeDirty_ComputedSideEffect - : DirtyLevels.MaybeDirty, - ), - ) - this.effect.computed = this - this.effect.active = this._cacheable = !isSSR - this[ReactiveFlags.IS_READONLY] = isReadonly + this.__v_isReadonly = !setter } - get value() { - // the computed ref may get wrapped by other proxies e.g. readonly() #3376 - const self = toRaw(this) - if ( - (!self._cacheable || self.effect.dirty) && - hasChanged(self._value, (self._value = self.effect.run()!)) - ) { - triggerRefValue(self, DirtyLevels.Dirty) - } - trackRefValue(self) - if (self.effect._dirtyLevel >= DirtyLevels.MaybeDirty_ComputedSideEffect) { - if (__DEV__ && (__TEST__ || this._warnRecursive)) { - warn(COMPUTED_SIDE_EFFECT_WARN, `\n\ngetter: `, this.getter) - } - triggerRefValue(self, DirtyLevels.MaybeDirty_ComputedSideEffect) + notify() { + // avoid infinite self recursion + if (activeSub !== this) { + this.flags |= EffectFlags.DIRTY + this.dep.notify() + } else if (__DEV__) { + // TODO warn } - return self._value - } - - set value(newValue: T) { - this._setter(newValue) } - // #region polyfill _dirty for backward compatibility third party code for Vue <= 3.3.x - get _dirty() { - return this.effect.dirty + get value() { + const link = __DEV__ + ? this.dep.track({ + target: this, + type: TrackOpTypes.GET, + key: 'value', + }) + : this.dep.track() + refreshComputed(this) + // sync version after evaluation + if (link) { + link.version = this.dep.version + } + return this._value } - set _dirty(v) { - this.effect.dirty = v + set value(newValue) { + if (this.setter) { + this.setter(newValue) + } else if (__DEV__) { + warn('Write operation failed: computed value is readonly') + } } - // #endregion } /** diff --cc packages/reactivity/src/index.ts index 40bdf7b1b0,505ec9e203..1b85e47b36 --- a/packages/reactivity/src/index.ts +++ b/packages/reactivity/src/index.ts @@@ -43,7 -43,9 +43,8 @@@ export type WritableComputedOptions, type ComputedGetter, type ComputedSetter, + type ComputedRefImpl, } from './computed' -export { deferredComputed } from './deferredComputed' export { effect, stop, diff --cc packages/reactivity/src/ref.ts index bfde3b787e,5f40fbb7c2..32f79217e7 --- a/packages/reactivity/src/ref.ts +++ b/packages/reactivity/src/ref.ts @@@ -15,8 -21,11 +15,9 @@@ import toRaw, toReactive, } from './reactive' -import type { ShallowReactiveMarker } from './reactive' -import { type Dep, createDep } from './dep' -import { ComputedRefImpl } from './computed' -import { getDepFromReactive } from './reactiveEffect' +import type { ComputedRef } from './computed' +import { TrackOpTypes, TriggerOpTypes } from './constants' + import { warn } from './warning' declare const RefSymbol: unique symbol export declare const RawSymbol: unique symbol