Skip to content

Commit 9fda941

Browse files
committed
feat(reactivity): add isShallow api
1 parent 0c06c74 commit 9fda941

File tree

9 files changed

+39
-15
lines changed

9 files changed

+39
-15
lines changed

packages/reactivity/__tests__/ref.spec.ts

+5
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
} from '../src/index'
1111
import { computed } from '@vue/runtime-dom'
1212
import { shallowRef, unref, customRef, triggerRef } from '../src/ref'
13+
import { isShallow } from '../src/reactive'
1314

1415
describe('reactivity/ref', () => {
1516
it('should hold a value', () => {
@@ -227,6 +228,10 @@ describe('reactivity/ref', () => {
227228
expect(dummy).toBe(2)
228229
})
229230

231+
test('shallowRef isShallow', () => {
232+
expect(isShallow(shallowRef({ a: 1 }))).toBe(true)
233+
})
234+
230235
test('isRef', () => {
231236
expect(isRef(ref(1))).toBe(true)
232237
expect(isRef(computed(() => 1))).toBe(true)

packages/reactivity/__tests__/shallowReactive.spec.ts

+12-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
import { isReactive, reactive, shallowReactive } from '../src/reactive'
1+
import {
2+
isReactive,
3+
isShallow,
4+
reactive,
5+
shallowReactive,
6+
shallowReadonly
7+
} from '../src/reactive'
28

39
import { effect } from '../src/effect'
410

@@ -24,6 +30,11 @@ describe('shallowReactive', () => {
2430
expect(isReactive(reactiveProxy.foo)).toBe(true)
2531
})
2632

33+
test('isShallow', () => {
34+
expect(isShallow(shallowReactive({}))).toBe(true)
35+
expect(isShallow(shallowReadonly({}))).toBe(true)
36+
})
37+
2738
describe('collections', () => {
2839
test('should be reactive', () => {
2940
const shallowSet = shallowReactive(new Set())

packages/reactivity/src/baseHandlers.ts

+2
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ function createGetter(isReadonly = false, shallow = false) {
8484
return !isReadonly
8585
} else if (key === ReactiveFlags.IS_READONLY) {
8686
return isReadonly
87+
} else if (key === ReactiveFlags.IS_SHALLOW) {
88+
return shallow
8789
} else if (
8890
key === ReactiveFlags.RAW &&
8991
receiver ===

packages/reactivity/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export {
2222
readonly,
2323
isReactive,
2424
isReadonly,
25+
isShallow,
2526
isProxy,
2627
shallowReactive,
2728
shallowReadonly,

packages/reactivity/src/reactive.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@ export const enum ReactiveFlags {
1717
SKIP = '__v_skip',
1818
IS_REACTIVE = '__v_isReactive',
1919
IS_READONLY = '__v_isReadonly',
20+
IS_SHALLOW = '__v_isShallow',
2021
RAW = '__v_raw'
2122
}
2223

2324
export interface Target {
2425
[ReactiveFlags.SKIP]?: boolean
2526
[ReactiveFlags.IS_REACTIVE]?: boolean
2627
[ReactiveFlags.IS_READONLY]?: boolean
28+
[ReactiveFlags.IS_SHALLOW]?: boolean
2729
[ReactiveFlags.RAW]?: any
2830
}
2931

@@ -87,7 +89,7 @@ export type UnwrapNestedRefs<T> = T extends Ref ? T : UnwrapRefSimple<T>
8789
export function reactive<T extends object>(target: T): UnwrapNestedRefs<T>
8890
export function reactive(target: object) {
8991
// if trying to observe a readonly proxy, return the readonly version.
90-
if (target && (target as Target)[ReactiveFlags.IS_READONLY]) {
92+
if (isReadonly(target)) {
9193
return target
9294
}
9395
return createReactiveObject(
@@ -226,6 +228,10 @@ export function isReadonly(value: unknown): boolean {
226228
return !!(value && (value as Target)[ReactiveFlags.IS_READONLY])
227229
}
228230

231+
export function isShallow(value: unknown): boolean {
232+
return !!(value && (value as Target)[ReactiveFlags.IS_SHALLOW])
233+
}
234+
229235
export function isProxy(value: unknown): boolean {
230236
return isReactive(value) || isReadonly(value)
231237
}

packages/reactivity/src/ref.ts

+5-9
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,6 @@ export interface Ref<T = any> {
1616
* autocomplete, so we use a private Symbol instead.
1717
*/
1818
[RefSymbol]: true
19-
/**
20-
* @internal
21-
*/
22-
_shallow?: boolean
2319
}
2420

2521
type RefBase<T> = {
@@ -102,9 +98,9 @@ class RefImpl<T> {
10298
public dep?: Dep = undefined
10399
public readonly __v_isRef = true
104100

105-
constructor(value: T, public readonly _shallow: boolean) {
106-
this._rawValue = _shallow ? value : toRaw(value)
107-
this._value = _shallow ? value : toReactive(value)
101+
constructor(value: T, public readonly __v_isShallow: boolean) {
102+
this._rawValue = __v_isShallow ? value : toRaw(value)
103+
this._value = __v_isShallow ? value : toReactive(value)
108104
}
109105

110106
get value() {
@@ -113,10 +109,10 @@ class RefImpl<T> {
113109
}
114110

115111
set value(newVal) {
116-
newVal = this._shallow ? newVal : toRaw(newVal)
112+
newVal = this.__v_isShallow ? newVal : toRaw(newVal)
117113
if (hasChanged(newVal, this._rawValue)) {
118114
this._rawValue = newVal
119-
this._value = this._shallow ? newVal : toReactive(newVal)
115+
this._value = this.__v_isShallow ? newVal : toReactive(newVal)
120116
triggerRefValue(this, newVal)
121117
}
122118
}

packages/runtime-core/src/apiWatch.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {
22
isRef,
3+
isShallow,
34
Ref,
45
ComputedRef,
56
ReactiveEffect,
@@ -205,7 +206,7 @@ function doWatch(
205206

206207
if (isRef(source)) {
207208
getter = () => source.value
208-
forceTrigger = !!source._shallow
209+
forceTrigger = isShallow(source)
209210
} else if (isReactive(source)) {
210211
getter = () => source
211212
deep = true

packages/runtime-core/src/customFormatter.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { isReactive, isReadonly, isRef, Ref, toRaw } from '@vue/reactivity'
22
import { EMPTY_OBJ, extend, isArray, isFunction, isObject } from '@vue/shared'
3+
import { isShallow } from '../../reactivity/src/reactive'
34
import { ComponentInternalInstance, ComponentOptions } from './component'
45
import { ComponentPublicInstance } from './componentPublicInstance'
56

@@ -38,7 +39,7 @@ export function initCustomFormatter() {
3839
return [
3940
'div',
4041
{},
41-
['span', vueStyle, 'Reactive'],
42+
['span', vueStyle, isShallow(obj) ? 'ShallowReactive' : 'Reactive'],
4243
'<',
4344
formatValue(obj),
4445
`>${isReadonly(obj) ? ` (readonly)` : ``}`
@@ -47,7 +48,7 @@ export function initCustomFormatter() {
4748
return [
4849
'div',
4950
{},
50-
['span', vueStyle, 'Readonly'],
51+
['span', vueStyle, isShallow(obj) ? 'ShallowReadonly' : 'Readonly'],
5152
'<',
5253
formatValue(obj),
5354
'>'
@@ -181,7 +182,7 @@ export function initCustomFormatter() {
181182
}
182183

183184
function genRefFlag(v: Ref) {
184-
if (v._shallow) {
185+
if (isShallow(v)) {
185186
return `ShallowRef`
186187
}
187188
if ((v as any).effect) {

packages/runtime-core/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export {
1515
isProxy,
1616
isReactive,
1717
isReadonly,
18+
isShallow,
1819
// advanced
1920
customRef,
2021
triggerRef,

0 commit comments

Comments
 (0)