import { TriggerOpTypes, TrackOpTypes } from './operations'
import { Ref } from './ref'
import { isFunction, NOOP } from '@vue/shared'
-import { ReactiveFlags } from './reactive'
+import { ReactiveFlags, toRaw } from './reactive'
export interface ComputedRef<T = any> extends WritableComputedRef<T> {
readonly value: T
set: ComputedSetter<T>
}
+class ComputedRefImpl<T> {
+ private _value!: T
+ private _dirty = true
+
+ public readonly effect: ReactiveEffect<T>
+
+ public readonly __v_isRef = true;
+ public readonly [ReactiveFlags.IS_READONLY]: boolean
+
+ constructor(
+ getter: ComputedGetter<T>,
+ private readonly _setter: ComputedSetter<T>,
+ isReadonly: boolean
+ ) {
+ this.effect = effect(getter, {
+ lazy: true,
+ scheduler: () => {
+ if (!this._dirty) {
+ this._dirty = true
+ trigger(toRaw(this), TriggerOpTypes.SET, 'value')
+ }
+ }
+ })
+
+ this[ReactiveFlags.IS_READONLY] = isReadonly
+ }
+
+ get value() {
+ if (this._dirty) {
+ this._value = this.effect()
+ this._dirty = false
+ }
+ track(toRaw(this), TrackOpTypes.GET, 'value')
+ return this._value
+ }
+
+ set value(newValue: T) {
+ this._setter(newValue)
+ }
+}
+
export function computed<T>(getter: ComputedGetter<T>): ComputedRef<T>
export function computed<T>(
options: WritableComputedOptions<T>
setter = getterOrOptions.set
}
- let dirty = true
- let value: T
- let computed: ComputedRef<T>
-
- const runner = effect(getter, {
- lazy: true,
- scheduler: () => {
- if (!dirty) {
- dirty = true
- trigger(computed, TriggerOpTypes.SET, 'value')
- }
- }
- })
- computed = {
- __v_isRef: true,
- [ReactiveFlags.IS_READONLY]:
- isFunction(getterOrOptions) || !getterOrOptions.set,
-
- // expose effect so computed can be stopped
- effect: runner,
- get value() {
- if (dirty) {
- value = runner()
- dirty = false
- }
- track(computed, TrackOpTypes.GET, 'value')
- return value
- },
- set value(newValue: T) {
- setter(newValue)
- }
- } as any
- return computed
+ return new ComputedRefImpl(
+ getter,
+ setter,
+ isFunction(getterOrOptions) || !getterOrOptions.set
+ ) as any
}
export function isRef<T>(r: Ref<T> | unknown): r is Ref<T>
export function isRef(r: any): r is Ref {
- return r ? r.__v_isRef === true : false
+ return Boolean(r && r.__v_isRef === true)
}
export function ref<T extends object>(
return createRef(value, true)
}
+class RefImpl<T> {
+ private _value: T
+
+ public readonly __v_isRef = true
+
+ constructor(private _rawValue: T, private readonly _shallow = false) {
+ this._value = _shallow ? _rawValue : convert(_rawValue)
+ }
+
+ get value() {
+ track(toRaw(this), TrackOpTypes.GET, 'value')
+ return this._value
+ }
+
+ set value(newVal) {
+ if (hasChanged(toRaw(newVal), this._rawValue)) {
+ this._rawValue = newVal
+ this._value = this._shallow ? newVal : convert(newVal)
+ trigger(toRaw(this), TriggerOpTypes.SET, 'value', newVal)
+ }
+ }
+}
+
function createRef(rawValue: unknown, shallow = false) {
if (isRef(rawValue)) {
return rawValue
}
- let value = shallow ? rawValue : convert(rawValue)
- const r = {
- __v_isRef: true,
- get value() {
- track(r, TrackOpTypes.GET, 'value')
- return value
- },
- set value(newVal) {
- if (hasChanged(toRaw(newVal), rawValue)) {
- rawValue = newVal
- value = shallow ? newVal : convert(newVal)
- trigger(r, TriggerOpTypes.SET, 'value', newVal)
- }
- }
- }
- return r
+ return new RefImpl(rawValue, shallow)
}
export function triggerRef(ref: Ref) {
set: (value: T) => void
}
-export function customRef<T>(factory: CustomRefFactory<T>): Ref<T> {
- const { get, set } = factory(
- () => track(r, TrackOpTypes.GET, 'value'),
- () => trigger(r, TriggerOpTypes.SET, 'value')
- )
- const r = {
- __v_isRef: true,
- get value() {
- return get()
- },
- set value(v) {
- set(v)
- }
+class CustomRefImpl<T> {
+ private readonly _get: ReturnType<CustomRefFactory<T>>['get']
+ private readonly _set: ReturnType<CustomRefFactory<T>>['set']
+
+ public readonly __v_isRef = true
+
+ constructor(factory: CustomRefFactory<T>) {
+ const { get, set } = factory(
+ () => track(this, TrackOpTypes.GET, 'value'),
+ () => trigger(this, TriggerOpTypes.SET, 'value')
+ )
+ this._get = get
+ this._set = set
+ }
+
+ get value() {
+ return this._get()
+ }
+
+ set value(newVal) {
+ this._set(newVal)
}
- return r as any
+}
+
+export function customRef<T>(factory: CustomRefFactory<T>): Ref<T> {
+ return new CustomRefImpl(factory) as any
}
export function toRefs<T extends object>(object: T): ToRefs<T> {
return ret
}
+class ObjectRefImpl<T extends object, K extends keyof T> {
+ public readonly __v_isRef = true
+
+ constructor(private readonly _object: T, private readonly _key: K) {}
+
+ get value() {
+ return this._object[this._key]
+ }
+
+ set value(newVal) {
+ this._object[this._key] = newVal
+ }
+}
+
export function toRef<T extends object, K extends keyof T>(
object: T,
key: K
): Ref<T[K]> {
- return {
- __v_isRef: true,
- get value(): any {
- return object[key]
- },
- set value(newVal) {
- object[key] = newVal
- }
- } as any
+ return new ObjectRefImpl(object, key) as any
}
// corner case when use narrows type