Browse Source

feat(reactivity): store value cache on CustomRefs impls (#11539)

Co-authored-by: Evan You <evan@vuejs.org>
Alex 1 year ago
parent
commit
e044b6e737
2 changed files with 42 additions and 3 deletions
  1. 34 0
      packages/reactivity/__tests__/ref.spec.ts
  2. 8 3
      packages/reactivity/src/ref.ts

+ 34 - 0
packages/reactivity/__tests__/ref.spec.ts

@@ -478,4 +478,38 @@ describe('reactivity/ref', () => {
     expect(toValue(c)).toBe(3)
     expect(toValue(d)).toBe(4)
   })
+
+  test('ref w/ customRef w/ getterRef w/ objectRef should store value cache', () => {
+    const refValue = ref(1)
+    // @ts-expect-error private field
+    expect(refValue._value).toBe(1)
+
+    let customRefValueCache = 0
+    const customRefValue = customRef((track, trigger) => {
+      return {
+        get() {
+          track()
+          return customRefValueCache
+        },
+        set(value: number) {
+          customRefValueCache = value
+          trigger()
+        },
+      }
+    })
+    customRefValue.value
+
+    // @ts-expect-error internal field
+    expect(customRefValue._value).toBe(0)
+
+    const getterRefValue = toRef(() => 1)
+    getterRefValue.value
+    // @ts-expect-error internal field
+    expect(getterRefValue._value).toBe(1)
+
+    const objectRefValue = toRef({ value: 1 }, 'value')
+    objectRefValue.value
+    // @ts-expect-error internal field
+    expect(objectRefValue._value).toBe(1)
+  })
 })

+ 8 - 3
packages/reactivity/src/ref.ts

@@ -287,6 +287,8 @@ class CustomRefImpl<T> {
 
   public readonly [ReactiveFlags.IS_REF] = true
 
+  public _value: T = undefined!
+
   constructor(factory: CustomRefFactory<T>) {
     const dep = (this.dep = new Dep())
     const { get, set } = factory(dep.track.bind(dep), dep.trigger.bind(dep))
@@ -295,7 +297,7 @@ class CustomRefImpl<T> {
   }
 
   get value() {
-    return this._get()
+    return (this._value = this._get())
   }
 
   set value(newVal) {
@@ -339,6 +341,7 @@ export function toRefs<T extends object>(object: T): ToRefs<T> {
 
 class ObjectRefImpl<T extends object, K extends keyof T> {
   public readonly [ReactiveFlags.IS_REF] = true
+  public _value: T[K] = undefined!
 
   constructor(
     private readonly _object: T,
@@ -348,7 +351,7 @@ class ObjectRefImpl<T extends object, K extends keyof T> {
 
   get value() {
     const val = this._object[this._key]
-    return val === undefined ? this._defaultValue! : val
+    return (this._value = val === undefined ? this._defaultValue! : val)
   }
 
   set value(newVal) {
@@ -363,9 +366,11 @@ class ObjectRefImpl<T extends object, K extends keyof T> {
 class GetterRefImpl<T> {
   public readonly [ReactiveFlags.IS_REF] = true
   public readonly [ReactiveFlags.IS_READONLY] = true
+  public _value: T = undefined!
+
   constructor(private readonly _getter: () => T) {}
   get value() {
-    return this._getter()
+    return (this._value = this._getter())
   }
 }