feat(reactivity): add shallowReactive function (#689)

This commit is contained in:
Dmitry Sharshakov 2020-02-04 18:15:27 +03:00 committed by GitHub
parent 2d56dfdc4f
commit 7f38c1e0ff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 44 additions and 3 deletions

View File

@ -1,5 +1,11 @@
import { ref, isRef } from '../src/ref' import { ref, isRef } from '../src/ref'
import { reactive, isReactive, toRaw, markNonReactive } from '../src/reactive' import {
reactive,
isReactive,
toRaw,
markNonReactive,
shallowReactive
} from '../src/reactive'
import { mockWarn } from '@vue/shared' import { mockWarn } from '@vue/shared'
import { computed } from '../src/computed' import { computed } from '../src/computed'
@ -212,4 +218,17 @@ describe('reactivity/reactive', () => {
expect(isReactive(obj.foo)).toBe(true) expect(isReactive(obj.foo)).toBe(true)
expect(isReactive(obj.bar)).toBe(false) expect(isReactive(obj.bar)).toBe(false)
}) })
describe('shallowReactive', () => {
test('should not make non-reactive properties reactive', () => {
const props = shallowReactive({ n: { foo: 1 } })
expect(isReactive(props.n)).toBe(false)
})
test('should keep reactive properties reactive', () => {
const props: any = shallowReactive({ n: reactive({ foo: 1 }) })
props.n = reactive({ foo: 2 })
expect(isReactive(props.n)).toBe(true)
})
})
}) })

View File

@ -12,6 +12,7 @@ const builtInSymbols = new Set(
) )
const get = /*#__PURE__*/ createGetter() const get = /*#__PURE__*/ createGetter()
const shallowReactiveGet = /*#__PURE__*/ createGetter(false, true)
const readonlyGet = /*#__PURE__*/ createGetter(true) const readonlyGet = /*#__PURE__*/ createGetter(true)
const shallowReadonlyGet = /*#__PURE__*/ createGetter(true, true) const shallowReadonlyGet = /*#__PURE__*/ createGetter(true, true)
@ -54,6 +55,7 @@ function createGetter(isReadonly = false, shallow = false) {
} }
const set = /*#__PURE__*/ createSetter() const set = /*#__PURE__*/ createSetter()
const shallowReactiveSet = /*#__PURE__*/ createSetter(false, true)
const readonlySet = /*#__PURE__*/ createSetter(true) const readonlySet = /*#__PURE__*/ createSetter(true)
const shallowReadonlySet = /*#__PURE__*/ createSetter(true, true) const shallowReadonlySet = /*#__PURE__*/ createSetter(true, true)
@ -165,6 +167,12 @@ export const readonlyHandlers: ProxyHandler<object> = {
} }
} }
export const shallowReactiveHandlers: ProxyHandler<object> = {
...mutableHandlers,
get: shallowReactiveGet,
set: shallowReactiveSet
}
// Props handlers are special in the sense that it should not unwrap top-level // Props handlers are special in the sense that it should not unwrap top-level
// refs (in order to allow refs to be explicitly passed down), but should // refs (in order to allow refs to be explicitly passed down), but should
// retain the reactivity of the normal readonly object. // retain the reactivity of the normal readonly object.

View File

@ -2,6 +2,7 @@ export { ref, isRef, toRefs, Ref, UnwrapRef } from './ref'
export { export {
reactive, reactive,
isReactive, isReactive,
shallowReactive,
readonly, readonly,
isReadonly, isReadonly,
shallowReadonly, shallowReadonly,

View File

@ -2,7 +2,8 @@ import { isObject, toRawType } from '@vue/shared'
import { import {
mutableHandlers, mutableHandlers,
readonlyHandlers, readonlyHandlers,
shallowReadonlyHandlers shallowReadonlyHandlers,
shallowReactiveHandlers
} from './baseHandlers' } from './baseHandlers'
import { import {
mutableCollectionHandlers, mutableCollectionHandlers,
@ -75,7 +76,6 @@ export function readonly<T extends object>(
) )
} }
// @internal
// Return a reactive-copy of the original object, where only the root level // Return a reactive-copy of the original object, where only the root level
// properties are readonly, and does NOT unwrap refs nor recursively convert // properties are readonly, and does NOT unwrap refs nor recursively convert
// returned properties. // returned properties.
@ -92,6 +92,19 @@ export function shallowReadonly<T extends object>(
) )
} }
// Return a reactive-copy of the original object, where only the root level
// properties are reactive, and does NOT unwrap refs nor recursively convert
// returned properties.
export function shallowReactive<T extends object>(target: T): T {
return createReactiveObject(
target,
rawToReactive,
reactiveToRaw,
shallowReactiveHandlers,
mutableCollectionHandlers
)
}
function createReactiveObject( function createReactiveObject(
target: unknown, target: unknown,
toProxy: WeakMap<any, any>, toProxy: WeakMap<any, any>,