feat(reactivity): add support for customRef API

This commit is contained in:
Evan You 2020-04-14 20:45:41 -04:00
parent 4046f0bc03
commit b83c580131
4 changed files with 68 additions and 4 deletions

View 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)
})
})

View 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,

View 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]> } {

View 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'