| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212 |
- import { isFunction } from '@vue/shared'
- import {
- type DebuggerEvent,
- type DebuggerOptions,
- EffectFlags,
- type Link,
- type Subscriber,
- activeSub,
- refreshComputed,
- } from './effect'
- import type { Ref } from './ref'
- import { warn } from './warning'
- import { Dep, globalVersion } from './dep'
- import { ReactiveFlags, TrackOpTypes } from './constants'
- declare const ComputedRefSymbol: unique symbol
- declare const WritableComputedRefSymbol: unique symbol
- interface BaseComputedRef<T, S = T> extends Ref<T, S> {
- [ComputedRefSymbol]: true
- /**
- * @deprecated computed no longer uses effect
- */
- effect: ComputedRefImpl
- }
- export interface ComputedRef<T = any> extends BaseComputedRef<T> {
- readonly value: T
- }
- export interface WritableComputedRef<T, S = T> extends BaseComputedRef<T, S> {
- [WritableComputedRefSymbol]: true
- }
- export type ComputedGetter<T> = (oldValue?: T) => T
- export type ComputedSetter<T> = (newValue: T) => void
- export interface WritableComputedOptions<T, S = T> {
- get: ComputedGetter<T>
- set: ComputedSetter<S>
- }
- /**
- * @private exported by @vue/reactivity for Vue core use, but not exported from
- * the main vue package
- */
- export class ComputedRefImpl<T = any> implements Subscriber {
- /**
- * @internal
- */
- _value: any = undefined
- /**
- * @internal
- */
- readonly dep: Dep = new Dep(this)
- /**
- * @internal
- */
- readonly __v_isRef = true
- // TODO isolatedDeclarations ReactiveFlags.IS_REF
- /**
- * @internal
- */
- readonly __v_isReadonly: boolean
- // TODO isolatedDeclarations ReactiveFlags.IS_READONLY
- // A computed is also a subscriber that tracks other deps
- /**
- * @internal
- */
- deps?: Link = undefined
- /**
- * @internal
- */
- depsTail?: Link = undefined
- /**
- * @internal
- */
- flags: EffectFlags = EffectFlags.DIRTY
- /**
- * @internal
- */
- globalVersion: number = globalVersion - 1
- /**
- * @internal
- */
- isSSR: boolean
- // for backwards compat
- effect: this = this
- // dev only
- onTrack?: (event: DebuggerEvent) => void
- // dev only
- onTrigger?: (event: DebuggerEvent) => void
- /**
- * Dev only
- * @internal
- */
- _warnRecursive?: boolean
- constructor(
- public fn: ComputedGetter<T>,
- private readonly setter: ComputedSetter<T> | undefined,
- isSSR: boolean,
- ) {
- this[ReactiveFlags.IS_READONLY] = !setter
- this.isSSR = isSSR
- }
- /**
- * @internal
- */
- notify(): void {
- this.flags |= EffectFlags.DIRTY
- // avoid infinite self recursion
- if (activeSub !== this) {
- this.dep.notify()
- } else if (__DEV__) {
- // TODO warn
- }
- }
- get value(): T {
- 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 value(newValue) {
- if (this.setter) {
- this.setter(newValue)
- } else if (__DEV__) {
- warn('Write operation failed: computed value is readonly')
- }
- }
- }
- /**
- * Takes a getter function and returns a readonly reactive ref object for the
- * returned value from the getter. It can also take an object with get and set
- * functions to create a writable ref object.
- *
- * @example
- * ```js
- * // Creating a readonly computed ref:
- * const count = ref(1)
- * const plusOne = computed(() => count.value + 1)
- *
- * console.log(plusOne.value) // 2
- * plusOne.value++ // error
- * ```
- *
- * ```js
- * // Creating a writable computed ref:
- * const count = ref(1)
- * const plusOne = computed({
- * get: () => count.value + 1,
- * set: (val) => {
- * count.value = val - 1
- * }
- * })
- *
- * plusOne.value = 1
- * console.log(count.value) // 0
- * ```
- *
- * @param getter - Function that produces the next value.
- * @param debugOptions - For debugging. See {@link https://vuejs.org/guide/extras/reactivity-in-depth.html#computed-debugging}.
- * @see {@link https://vuejs.org/api/reactivity-core.html#computed}
- */
- export function computed<T>(
- getter: ComputedGetter<T>,
- debugOptions?: DebuggerOptions,
- ): ComputedRef<T>
- export function computed<T, S = T>(
- options: WritableComputedOptions<T, S>,
- debugOptions?: DebuggerOptions,
- ): WritableComputedRef<T, S>
- export function computed<T>(
- getterOrOptions: ComputedGetter<T> | WritableComputedOptions<T>,
- debugOptions?: DebuggerOptions,
- isSSR = false,
- ) {
- let getter: ComputedGetter<T>
- let setter: ComputedSetter<T> | undefined
- if (isFunction(getterOrOptions)) {
- getter = getterOrOptions
- } else {
- getter = getterOrOptions.get
- setter = getterOrOptions.set
- }
- const cRef = new ComputedRefImpl(getter, setter, isSSR)
- if (__DEV__ && debugOptions && !isSSR) {
- cRef.onTrack = debugOptions.onTrack
- cRef.onTrigger = debugOptions.onTrigger
- }
- return cRef as any
- }
|