Skip to content

Commit 351ce06

Browse files
committed
fix(compat): watch arrays as deep: 1
1 parent 5d04c06 commit 351ce06

File tree

4 files changed

+434
-86
lines changed

4 files changed

+434
-86
lines changed

packages/reactivity/src/watch.ts

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,8 @@ export function watch(
245245
forceTrigger ||
246246
(isMultiSource
247247
? (newValue as any[]).some((v, i) => hasChanged(v, oldValue[i]))
248-
: hasChanged(newValue, oldValue))
248+
: hasChanged(newValue, oldValue)) ||
249+
(__COMPAT__ && (options as any).compatWatchArray && isArray(newValue))
249250
) {
250251
// cleanup before running cb again
251252
if (cleanup) {
@@ -264,15 +265,6 @@ export function watch(
264265
: oldValue,
265266
boundCleanup,
266267
]
267-
268-
if (__COMPAT__) {
269-
for (let i = 0; i < args.length - 1; i++) {
270-
if (args[i] && args[i].WATCH_ARRAY_UNWRAP) {
271-
args[i] = args[i].WATCH_ARRAY_UNWRAP
272-
}
273-
}
274-
}
275-
276268
oldValue = newValue
277269
call
278270
? call(cb!, WatchErrorCodes.WATCH_CALLBACK, args)

packages/runtime-core/src/apiWatch.ts

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,17 @@ import {
77
type WatchHandle,
88
type WatchSource,
99
watch as baseWatch,
10+
traverse,
1011
} from '@vue/reactivity'
1112
import { type SchedulerJob, SchedulerJobFlags, queueJob } from './scheduler'
12-
import { EMPTY_OBJ, NOOP, extend, isFunction, isString } from '@vue/shared'
13+
import {
14+
EMPTY_OBJ,
15+
NOOP,
16+
extend,
17+
isArray,
18+
isFunction,
19+
isString,
20+
} from '@vue/shared'
1321
import {
1422
type ComponentInternalInstance,
1523
currentInstance,
@@ -19,6 +27,11 @@ import {
1927
import { callWithAsyncErrorHandling } from './errorHandling'
2028
import { queuePostRenderEffect } from './renderer'
2129
import { warn } from './warning'
30+
import {
31+
DeprecationTypes,
32+
checkCompatEnabled,
33+
isCompatEnabled,
34+
} from './compat/compatConfig'
2235
import type { ObjectWatchOptionItem } from './componentOptions'
2336
import { useSSRContext } from './helpers/useSsrContext'
2437

@@ -236,6 +249,22 @@ function doWatch(
236249
return watchHandle
237250
}
238251

252+
export function createCompatWatchGetter(
253+
baseGetter: () => any,
254+
instance: ComponentInternalInstance,
255+
) {
256+
return (): any => {
257+
const val = baseGetter()
258+
if (
259+
isArray(val) &&
260+
checkCompatEnabled(DeprecationTypes.WATCH_ARRAY, instance)
261+
) {
262+
traverse(val, 1)
263+
}
264+
return val
265+
}
266+
}
267+
239268
// this.$watch
240269
export function instanceWatch(
241270
this: ComponentInternalInstance,
@@ -244,7 +273,7 @@ export function instanceWatch(
244273
options?: WatchOptions,
245274
): WatchHandle {
246275
const publicThis = this.proxy as any
247-
const getter = isString(source)
276+
let getter = isString(source)
248277
? source.includes('.')
249278
? createPathGetter(publicThis, source)
250279
: () => publicThis[source]
@@ -256,6 +285,19 @@ export function instanceWatch(
256285
cb = value.handler as Function
257286
options = value
258287
}
288+
289+
if (
290+
__COMPAT__ &&
291+
isString(source) &&
292+
isCompatEnabled(DeprecationTypes.WATCH_ARRAY, this)
293+
) {
294+
const deep = options && options.deep
295+
if (!deep) {
296+
options = extend({ compatWatchArray: true }, options)
297+
getter = createCompatWatchGetter(getter, this)
298+
}
299+
}
300+
259301
const reset = setCurrentInstance(this)
260302
const res = doWatch(getter, cb.bind(publicThis), options)
261303
reset()

packages/runtime-core/src/componentOptions.ts

Lines changed: 20 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
import {
2-
type Component,
3-
type ComponentInternalInstance,
4-
type ComponentInternalOptions,
5-
type ConcreteComponent,
6-
type Data,
7-
type InternalRenderFunction,
8-
type SetupContext,
9-
currentInstance,
1+
import type {
2+
Component,
3+
ComponentInternalInstance,
4+
ComponentInternalOptions,
5+
ConcreteComponent,
6+
Data,
7+
InternalRenderFunction,
8+
SetupContext,
109
} from './component'
1110
import {
1211
type LooseRequired,
@@ -19,11 +18,12 @@ import {
1918
isPromise,
2019
isString,
2120
} from '@vue/shared'
22-
import { type Ref, getCurrentScope, isRef, traverse } from '@vue/reactivity'
21+
import { type Ref, isRef } from '@vue/reactivity'
2322
import { computed } from './apiComputed'
2423
import {
2524
type WatchCallback,
2625
type WatchOptions,
26+
createCompatWatchGetter,
2727
createPathGetter,
2828
watch,
2929
} from './apiWatch'
@@ -72,9 +72,9 @@ import { warn } from './warning'
7272
import type { VNodeChild } from './vnode'
7373
import { callWithAsyncErrorHandling } from './errorHandling'
7474
import { deepMergeData } from './compat/data'
75-
import { DeprecationTypes, checkCompatEnabled } from './compat/compatConfig'
7675
import {
7776
type CompatConfig,
77+
DeprecationTypes,
7878
isCompatEnabled,
7979
softAssertCompatEnabled,
8080
} from './compat/compatConfig'
@@ -843,7 +843,7 @@ function callHook(
843843
)
844844
}
845845

846-
export function createWatcher(
846+
function createWatcher(
847847
raw: ComponentWatchOptionItem,
848848
ctx: Data,
849849
publicThis: ComponentPublicInstance,
@@ -854,23 +854,14 @@ export function createWatcher(
854854
: () => (publicThis as any)[key]
855855

856856
const options: WatchOptions = {}
857-
if (__COMPAT__) {
858-
const instance =
859-
currentInstance && getCurrentScope() === currentInstance.scope
860-
? currentInstance
861-
: null
862-
863-
const baseGetter = getter
864-
getter = () => {
865-
const val = baseGetter()
866-
if (
867-
isArray(val) &&
868-
checkCompatEnabled(DeprecationTypes.WATCH_ARRAY, instance)
869-
) {
870-
traverse(val, 1)
871-
return { WATCH_ARRAY_UNWRAP: val }
872-
}
873-
return val
857+
if (
858+
__COMPAT__ &&
859+
isCompatEnabled(DeprecationTypes.WATCH_ARRAY, publicThis.$)
860+
) {
861+
const deep = isObject(raw) && !isArray(raw) && !isFunction(raw) && raw.deep
862+
if (!deep) {
863+
;(options as any).compatWatchArray = true
864+
getter = createCompatWatchGetter(getter, publicThis.$)
874865
}
875866
}
876867

0 commit comments

Comments
 (0)