From: Evan You Date: Wed, 15 Apr 2020 00:45:41 +0000 (-0400) Subject: feat(reactivity): add support for `customRef` API X-Git-Tag: v3.0.0-alpha.13~8 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b83c5801315e5e28ac51ecff743206e665f4d868;p=thirdparty%2Fvuejs%2Fcore.git feat(reactivity): add support for `customRef` API --- diff --git a/packages/reactivity/__tests__/ref.spec.ts b/packages/reactivity/__tests__/ref.spec.ts index 6620f7fd9c..9ebe8f46ea 100644 --- a/packages/reactivity/__tests__/ref.spec.ts +++ b/packages/reactivity/__tests__/ref.spec.ts @@ -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) + }) }) diff --git a/packages/reactivity/src/index.ts b/packages/reactivity/src/index.ts index 91b1829e0d..d83b0f3058 100644 --- a/packages/reactivity/src/index.ts +++ b/packages/reactivity/src/index.ts @@ -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, diff --git a/packages/reactivity/src/ref.ts b/packages/reactivity/src/ref.ts index 05304ad7ef..bbbd94841a 100644 --- a/packages/reactivity/src/ref.ts +++ b/packages/reactivity/src/ref.ts @@ -70,6 +70,31 @@ export function unref(ref: T): T extends Ref ? V : T { return isRef(ref) ? (ref.value as any) : ref } +export type CustomRefFactory = ( + track: () => void, + trigger: () => void +) => { + get: () => T + set: (value: T) => void +} + +export function customRef(factory: CustomRefFactory): Ref { + 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( object: T ): { [K in keyof T]: Ref } { diff --git a/packages/runtime-core/src/index.ts b/packages/runtime-core/src/index.ts index 334b7c6f3b..2b4923e232 100644 --- a/packages/runtime-core/src/index.ts +++ b/packages/runtime-core/src/index.ts @@ -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'