]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
feat(reactivity): add support for `customRef` API
authorEvan You <yyx990803@gmail.com>
Wed, 15 Apr 2020 00:45:41 +0000 (20:45 -0400)
committerEvan You <yyx990803@gmail.com>
Wed, 15 Apr 2020 00:45:46 +0000 (20:45 -0400)
packages/reactivity/__tests__/ref.spec.ts
packages/reactivity/src/index.ts
packages/reactivity/src/ref.ts
packages/runtime-core/src/index.ts

index 6620f7fd9ce6cb2f227803aea047a211a7df902e..9ebe8f46ea69f2bea9dc65a53190b90582c871c6 100644 (file)
@@ -8,7 +8,7 @@ import {
   isReactive
 } from '../src/index'
 import { computed } from '@vue/runtime-dom'
-import { shallowRef, unref } from '../src/ref'
+import { shallowRef, unref, customRef } from '../src/ref'
 
 describe('reactivity/ref', () => {
   it('should hold a value', () => {
@@ -208,4 +208,33 @@ describe('reactivity/ref', () => {
     expect(dummyX).toBe(4)
     expect(dummyY).toBe(5)
   })
+
+  test('customRef', () => {
+    let value = 1
+    let _trigger: () => void
+
+    const custom = customRef((track, trigger) => ({
+      get() {
+        track()
+        return value
+      },
+      set(newValue: number) {
+        value = newValue
+        _trigger = trigger
+      }
+    }))
+
+    let dummy
+    effect(() => {
+      dummy = custom.value
+    })
+    expect(dummy).toBe(1)
+
+    custom.value = 2
+    // should not trigger yet
+    expect(dummy).toBe(1)
+
+    _trigger!()
+    expect(dummy).toBe(2)
+  })
 })
index 91b1829e0dee3ca5dfaf4fefdb543ccab03820c6..d83b0f305853d37344728b212fa6a8d1556783ea 100644 (file)
@@ -1,4 +1,13 @@
-export { ref, unref, shallowRef, isRef, toRefs, Ref, UnwrapRef } from './ref'
+export {
+  ref,
+  unref,
+  shallowRef,
+  isRef,
+  toRefs,
+  customRef,
+  Ref,
+  UnwrapRef
+} from './ref'
 export {
   reactive,
   isReactive,
index 05304ad7ef90384bfc954c840d7a869d6fd67fc7..bbbd94841a344ea8de182dfd73cd380669559cc3 100644 (file)
@@ -70,6 +70,31 @@ export function unref<T>(ref: T): T extends Ref<infer V> ? V : T {
   return isRef(ref) ? (ref.value as any) : ref
 }
 
+export type CustomRefFactory<T> = (
+  track: () => void,
+  trigger: () => void
+) => {
+  get: () => T
+  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 = {
+    _isRef: true,
+    get value() {
+      return get()
+    },
+    set value(v) {
+      set(v)
+    }
+  }
+  return r as any
+}
+
 export function toRefs<T extends object>(
   object: T
 ): { [K in keyof T]: Ref<T[K]> } {
index 334b7c6f3b5aa109cccefbab9d608a94215855da..2b4923e2323d4a978474728984d805ba31dc9c05 100644 (file)
@@ -7,13 +7,14 @@ export {
   shallowRef,
   isRef,
   toRefs,
+  customRef,
   reactive,
   isReactive,
   readonly,
   isReadonly,
   shallowReactive,
-  toRaw,
-  markNonReactive
+  markNonReactive,
+  toRaw
 } from '@vue/reactivity'
 export { computed } from './apiComputed'
 export { watch, watchEffect } from './apiWatch'