feat(reactivity): expose unref and shallowRef
This commit is contained in:
parent
0c67201942
commit
e9024bf1b7
@ -1,5 +1,14 @@
|
||||
import { ref, effect, reactive, isRef, toRefs, Ref } from '../src/index'
|
||||
import {
|
||||
ref,
|
||||
effect,
|
||||
reactive,
|
||||
isRef,
|
||||
toRefs,
|
||||
Ref,
|
||||
isReactive
|
||||
} from '../src/index'
|
||||
import { computed } from '@vue/runtime-dom'
|
||||
import { shallowRef, unref } from '../src/ref'
|
||||
|
||||
describe('reactivity/ref', () => {
|
||||
it('should hold a value', () => {
|
||||
@ -129,6 +138,26 @@ describe('reactivity/ref', () => {
|
||||
expect(tupleRef.value[4].value).toBe(1)
|
||||
})
|
||||
|
||||
test('unref', () => {
|
||||
expect(unref(1)).toBe(1)
|
||||
expect(unref(ref(1))).toBe(1)
|
||||
})
|
||||
|
||||
test('shallowRef', () => {
|
||||
const sref = shallowRef({ a: 1 })
|
||||
expect(isReactive(sref.value)).toBe(false)
|
||||
|
||||
let dummy
|
||||
effect(() => {
|
||||
dummy = sref.value.a
|
||||
})
|
||||
expect(dummy).toBe(1)
|
||||
|
||||
sref.value = { a: 2 }
|
||||
expect(isReactive(sref.value)).toBe(false)
|
||||
expect(dummy).toBe(2)
|
||||
})
|
||||
|
||||
test('isRef', () => {
|
||||
expect(isRef(ref(1))).toBe(true)
|
||||
expect(isRef(computed(() => 1))).toBe(true)
|
||||
|
@ -1,4 +1,4 @@
|
||||
export { ref, isRef, toRefs, Ref, UnwrapRef } from './ref'
|
||||
export { ref, unref, shallowRef, isRef, toRefs, Ref, UnwrapRef } from './ref'
|
||||
export {
|
||||
reactive,
|
||||
isReactive,
|
||||
|
@ -31,10 +31,22 @@ export function isRef(r: any): r is Ref {
|
||||
export function ref<T>(value: T): T extends Ref ? T : Ref<T>
|
||||
export function ref<T = any>(): Ref<T>
|
||||
export function ref(value?: unknown) {
|
||||
return createRef(value)
|
||||
}
|
||||
|
||||
export function shallowRef<T>(value: T): T extends Ref ? T : Ref<T>
|
||||
export function shallowRef<T = any>(): Ref<T>
|
||||
export function shallowRef(value?: unknown) {
|
||||
return createRef(value, true)
|
||||
}
|
||||
|
||||
function createRef(value: unknown, shallow = false) {
|
||||
if (isRef(value)) {
|
||||
return value
|
||||
}
|
||||
value = convert(value)
|
||||
if (!shallow) {
|
||||
value = convert(value)
|
||||
}
|
||||
const r = {
|
||||
_isRef: true,
|
||||
get value() {
|
||||
@ -42,7 +54,7 @@ export function ref(value?: unknown) {
|
||||
return value
|
||||
},
|
||||
set value(newVal) {
|
||||
value = convert(newVal)
|
||||
value = shallow ? newVal : convert(newVal)
|
||||
trigger(
|
||||
r,
|
||||
TriggerOpTypes.SET,
|
||||
@ -54,6 +66,10 @@ export function ref(value?: unknown) {
|
||||
return r
|
||||
}
|
||||
|
||||
export function unref<T>(ref: T): T extends Ref<infer V> ? V : T {
|
||||
return isRef(ref) ? (ref.value as any) : ref
|
||||
}
|
||||
|
||||
export function toRefs<T extends object>(
|
||||
object: T
|
||||
): { [K in keyof T]: Ref<T[K]> } {
|
||||
|
@ -13,7 +13,8 @@ import {
|
||||
isRef,
|
||||
isReactive,
|
||||
Ref,
|
||||
ComputedRef
|
||||
ComputedRef,
|
||||
unref
|
||||
} from '@vue/reactivity'
|
||||
import { warn } from './warning'
|
||||
import { Slots } from './componentSlots'
|
||||
@ -84,8 +85,6 @@ const enum AccessTypes {
|
||||
OTHER
|
||||
}
|
||||
|
||||
const unwrapRef = (val: unknown) => (isRef(val) ? val.value : val)
|
||||
|
||||
export const PublicInstanceProxyHandlers: ProxyHandler<any> = {
|
||||
get(target: ComponentInternalInstance, key: string) {
|
||||
// fast path for unscopables when using `with` block
|
||||
@ -115,7 +114,7 @@ export const PublicInstanceProxyHandlers: ProxyHandler<any> = {
|
||||
case AccessTypes.DATA:
|
||||
return data[key]
|
||||
case AccessTypes.CONTEXT:
|
||||
return unwrapRef(renderContext[key])
|
||||
return unref(renderContext[key])
|
||||
case AccessTypes.PROPS:
|
||||
return propsProxy![key]
|
||||
// default: just fallthrough
|
||||
@ -125,7 +124,7 @@ export const PublicInstanceProxyHandlers: ProxyHandler<any> = {
|
||||
return data[key]
|
||||
} else if (hasOwn(renderContext, key)) {
|
||||
accessCache![key] = AccessTypes.CONTEXT
|
||||
return unwrapRef(renderContext[key])
|
||||
return unref(renderContext[key])
|
||||
} else if (type.props != null) {
|
||||
// only cache other properties when instance has declared (this stable)
|
||||
// props
|
||||
|
@ -3,6 +3,8 @@
|
||||
export const version = __VERSION__
|
||||
export {
|
||||
ref,
|
||||
unref,
|
||||
shallowRef,
|
||||
isRef,
|
||||
toRefs,
|
||||
reactive,
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { expectType } from 'tsd'
|
||||
import { Ref, ref } from './index'
|
||||
import { isRef } from '@vue/reactivity'
|
||||
import { Ref, ref, isRef, unref } from './index'
|
||||
|
||||
function foo(arg: number | Ref<number>) {
|
||||
// ref coercing
|
||||
@ -11,6 +10,9 @@ function foo(arg: number | Ref<number>) {
|
||||
if (isRef(arg)) {
|
||||
expectType<Ref<number>>(arg)
|
||||
}
|
||||
|
||||
// ref unwrapping
|
||||
expectType<number>(unref(arg))
|
||||
}
|
||||
|
||||
foo(1)
|
||||
|
Loading…
Reference in New Issue
Block a user