]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
feat(reactivity): `proxyRefs` method and `ShallowUnwrapRefs` type (#1682)
authorEvan You <yyx990803@gmail.com>
Tue, 28 Jul 2020 20:30:56 +0000 (16:30 -0400)
committerGitHub <noreply@github.com>
Tue, 28 Jul 2020 20:30:56 +0000 (16:30 -0400)
* feat(reactivity): `proxyRefs` method and `ShallowUnwrapRefs` type

BREAKING CHANGE: template auto ref unwrapping are now applied shallowly,
i.e. only at the root level. See https://github.com/vuejs/vue-next/pull/1682 for
more details.

packages/reactivity/src/index.ts
packages/reactivity/src/ref.ts
packages/runtime-core/src/component.ts
packages/runtime-core/src/componentProxy.ts
packages/runtime-core/src/index.ts
test-dts/defineComponent.test-d.tsx

index aaf53242592b899907586eff794209fa56dd0551..b03e916d14a14db44ddbc2a30a4068dbc82848bf 100644 (file)
@@ -1,15 +1,17 @@
 export {
   ref,
-  unref,
   shallowRef,
   isRef,
   toRef,
   toRefs,
+  unref,
+  proxyRefs,
   customRef,
   triggerRef,
   Ref,
-  UnwrapRef,
   ToRefs,
+  UnwrapRef,
+  ShallowUnwrapRef,
   RefUnwrapBailTypes
 } from './ref'
 export {
index 25473b4cc8c0abcc991317a1a90aa064f90cb91c..174494e87e96b0e1077da24d909dbc61f88ff379 100644 (file)
@@ -1,7 +1,7 @@
 import { track, trigger } from './effect'
 import { TrackOpTypes, TriggerOpTypes } from './operations'
 import { isObject, hasChanged } from '@vue/shared'
-import { reactive, isProxy, toRaw } from './reactive'
+import { reactive, isProxy, toRaw, isReactive } from './reactive'
 import { CollectionTypes } from './collectionHandlers'
 
 declare const RefSymbol: unique symbol
@@ -71,6 +71,27 @@ export function unref<T>(ref: T): T extends Ref<infer V> ? V : T {
   return isRef(ref) ? (ref.value as any) : ref
 }
 
+const shallowUnwrapHandlers: ProxyHandler<any> = {
+  get: (target, key, receiver) => unref(Reflect.get(target, key, receiver)),
+  set: (target, key, value, receiver) => {
+    const oldValue = target[key]
+    if (isRef(oldValue) && !isRef(value)) {
+      oldValue.value = value
+      return true
+    } else {
+      return Reflect.set(target, key, value, receiver)
+    }
+  }
+}
+
+export function proxyRefs<T extends object>(
+  objectWithRefs: T
+): ShallowUnwrapRef<T> {
+  return isReactive(objectWithRefs)
+    ? objectWithRefs
+    : new Proxy(objectWithRefs, shallowUnwrapHandlers)
+}
+
 export type CustomRefFactory<T> = (
   track: () => void,
   trigger: () => void
@@ -146,6 +167,10 @@ type BaseTypes = string | number | boolean
  */
 export interface RefUnwrapBailTypes {}
 
+export type ShallowUnwrapRef<T> = {
+  [K in keyof T]: T[K] extends Ref<infer V> ? V : T[K]
+}
+
 export type UnwrapRef<T> = T extends Ref<infer V>
   ? UnwrapRefSimple<V>
   : UnwrapRefSimple<T>
index c0ea6ab3f3dc3c34a8d0107c1d7b43c7408a1b2c..12eaa76bc935d2dfd97b1d59f35bb81b25d02bc3 100644 (file)
@@ -1,10 +1,10 @@
 import { VNode, VNodeChild, isVNode } from './vnode'
 import {
-  reactive,
   ReactiveEffect,
   pauseTracking,
   resetTracking,
-  shallowReadonly
+  shallowReadonly,
+  proxyRefs
 } from '@vue/reactivity'
 import {
   CreateComponentPublicInstance,
@@ -548,7 +548,7 @@ export function handleSetupResult(
     }
     // setup returned bindings.
     // assuming a render function compiled from template is present.
-    instance.setupState = reactive(setupResult)
+    instance.setupState = proxyRefs(setupResult)
     if (__DEV__) {
       exposeSetupStateOnRenderContext(instance)
     }
index d2b78318ef7b39b7994da4be2c924613254c88cd..e043d93eb4b6cf610da333189d97986c0d4d8fac 100644 (file)
@@ -10,12 +10,12 @@ import {
 } from '@vue/shared'
 import {
   ReactiveEffect,
-  UnwrapRef,
   toRaw,
   shallowReadonly,
   ReactiveFlags,
   track,
-  TrackOpTypes
+  TrackOpTypes,
+  ShallowUnwrapRef
 } from '@vue/reactivity'
 import {
   ExtractComputedReturns,
@@ -154,7 +154,7 @@ export type ComponentPublicInstance<
   $nextTick: typeof nextTick
   $watch: typeof instanceWatch
 } & P &
-  UnwrapRef<B> &
+  ShallowUnwrapRef<B> &
   D &
   ExtractComputedReturns<C> &
   M &
index 757a21382bcaea9c0a23542113e0e8926f79f343..14283b5d46bb991ce8410bd6ee41389ae3eb6434 100644 (file)
@@ -8,6 +8,7 @@ export {
   readonly,
   // utilities
   unref,
+  proxyRefs,
   isRef,
   toRef,
   toRefs,
@@ -125,6 +126,7 @@ export {
   ComputedRef,
   WritableComputedRef,
   UnwrapRef,
+  ShallowUnwrapRef,
   WritableComputedOptions,
   ToRefs,
   DeepReadonly
index dcbad6a0fad6ded703540da62a1ad011137e437d..f7dacfcbe21e93e8551f15fabb8f9bde36462be3 100644 (file)
@@ -146,7 +146,7 @@ describe('with object props', () => {
 
       // assert setup context unwrapping
       expectType<number>(this.c)
-      expectType<string>(this.d.e)
+      expectType<string>(this.d.e.value)
       expectType<GT>(this.f.g)
 
       // setup context properties should be mutable