Skip to content

refactor(reactivity): encapsulate reactive handlers in class #8586

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 22, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 55 additions & 58 deletions packages/reactivity/src/baseHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import {
hasChanged,
isArray,
isIntegerKey,
extend,
makeMap
} from '@vue/shared'
import { isRef } from './ref'
Expand All @@ -45,11 +44,6 @@ const builtInSymbols = new Set(
.filter(isSymbol)
)

const get = /*#__PURE__*/ createGetter()
const shallowGet = /*#__PURE__*/ createGetter(false, true)
const readonlyGet = /*#__PURE__*/ createGetter(true)
const shallowReadonlyGet = /*#__PURE__*/ createGetter(true, true)

const arrayInstrumentations = /*#__PURE__*/ createArrayInstrumentations()

function createArrayInstrumentations() {
Expand Down Expand Up @@ -91,8 +85,15 @@ function hasOwnProperty(this: object, key: string) {
return obj.hasOwnProperty(key)
}

function createGetter(isReadonly = false, shallow = false) {
return function get(target: Target, key: string | symbol, receiver: object) {
class BaseReactiveHandler implements ProxyHandler<Target> {
constructor(
protected readonly _isReadonly = false,
protected readonly _shallow = false
) {}

get(target: Target, key: string | symbol, receiver: object) {
const isReadonly = this._isReadonly,
shallow = this._shallow
if (key === ReactiveFlags.IS_REACTIVE) {
return !isReadonly
} else if (key === ReactiveFlags.IS_READONLY) {
Expand Down Expand Up @@ -155,11 +156,12 @@ function createGetter(isReadonly = false, shallow = false) {
}
}

const set = /*#__PURE__*/ createSetter()
const shallowSet = /*#__PURE__*/ createSetter(true)
class MutableReactiveHandler extends BaseReactiveHandler {
constructor(shallow = false) {
super(false, shallow)
}

function createSetter(shallow = false) {
return function set(
set(
target: object,
key: string | symbol,
value: unknown,
Expand All @@ -169,7 +171,7 @@ function createSetter(shallow = false) {
if (isReadonly(oldValue) && isRef(oldValue) && !isRef(value)) {
return false
}
if (!shallow) {
if (!this._shallow) {
if (!isShallow(value) && !isReadonly(value)) {
oldValue = toRaw(oldValue)
value = toRaw(value)
Expand Down Expand Up @@ -197,51 +199,50 @@ function createSetter(shallow = false) {
}
return result
}
}

function deleteProperty(target: object, key: string | symbol): boolean {
const hadKey = hasOwn(target, key)
const oldValue = (target as any)[key]
const result = Reflect.deleteProperty(target, key)
if (result && hadKey) {
trigger(target, TriggerOpTypes.DELETE, key, undefined, oldValue)
deleteProperty(target: object, key: string | symbol): boolean {
const hadKey = hasOwn(target, key)
const oldValue = (target as any)[key]
const result = Reflect.deleteProperty(target, key)
if (result && hadKey) {
trigger(target, TriggerOpTypes.DELETE, key, undefined, oldValue)
}
return result
}
return result
}

function has(target: object, key: string | symbol): boolean {
const result = Reflect.has(target, key)
if (!isSymbol(key) || !builtInSymbols.has(key)) {
track(target, TrackOpTypes.HAS, key)
has(target: object, key: string | symbol): boolean {
const result = Reflect.has(target, key)
if (!isSymbol(key) || !builtInSymbols.has(key)) {
track(target, TrackOpTypes.HAS, key)
}
return result
}
ownKeys(target: object): (string | symbol)[] {
track(
target,
TrackOpTypes.ITERATE,
isArray(target) ? 'length' : ITERATE_KEY
)
return Reflect.ownKeys(target)
}
return result
}

function ownKeys(target: object): (string | symbol)[] {
track(target, TrackOpTypes.ITERATE, isArray(target) ? 'length' : ITERATE_KEY)
return Reflect.ownKeys(target)
}

export const mutableHandlers: ProxyHandler<object> = {
get,
set,
deleteProperty,
has,
ownKeys
}
class ReadonlyReactiveHandler extends BaseReactiveHandler {
constructor(shallow = false) {
super(true, shallow)
}

export const readonlyHandlers: ProxyHandler<object> = {
get: readonlyGet,
set(target, key) {
set(target: object, key: string | symbol) {
if (__DEV__) {
warn(
`Set operation on key "${String(key)}" failed: target is readonly.`,
target
)
}
return true
},
deleteProperty(target, key) {
}

deleteProperty(target: object, key: string | symbol) {
if (__DEV__) {
warn(
`Delete operation on key "${String(key)}" failed: target is readonly.`,
Expand All @@ -252,22 +253,18 @@ export const readonlyHandlers: ProxyHandler<object> = {
}
}

export const shallowReactiveHandlers = /*#__PURE__*/ extend(
{},
mutableHandlers,
{
get: shallowGet,
set: shallowSet
}
export const mutableHandlers: ProxyHandler<object> =
/*#__PURE__*/ new MutableReactiveHandler()

export const readonlyHandlers: ProxyHandler<object> =
/*#__PURE__*/ new ReadonlyReactiveHandler()

export const shallowReactiveHandlers = /*#__PURE__*/ new MutableReactiveHandler(
true
)

// 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
// retain the reactivity of the normal readonly object.
export const shallowReadonlyHandlers = /*#__PURE__*/ extend(
{},
readonlyHandlers,
{
get: shallowReadonlyGet
}
)
export const shallowReadonlyHandlers =
/*#__PURE__*/ new ReadonlyReactiveHandler(true)