From 2937530beff5c6bb57286c2556307859e37aa809 Mon Sep 17 00:00:00 2001 From: Evan You Date: Thu, 15 Jul 2021 12:14:19 -0400 Subject: [PATCH] fix(v-model): handle mutations of v-model bound array/sets fix #4096 --- packages/runtime-core/src/apiWatch.ts | 12 ++++++------ packages/runtime-core/src/directives.ts | 5 +++++ packages/runtime-dom/src/directives/vModel.ts | 4 ++++ 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/packages/runtime-core/src/apiWatch.ts b/packages/runtime-core/src/apiWatch.ts index 34c8deb1eaa..2abc4e1447f 100644 --- a/packages/runtime-core/src/apiWatch.ts +++ b/packages/runtime-core/src/apiWatch.ts @@ -390,12 +390,12 @@ export function createPathGetter(ctx: any, path: string) { } } -function traverse(value: unknown, seen: Set = new Set()) { - if ( - !isObject(value) || - seen.has(value) || - (value as any)[ReactiveFlags.SKIP] - ) { +export function traverse(value: unknown, seen: Set = new Set()) { + if (!isObject(value) || (value as any)[ReactiveFlags.SKIP]) { + return value + } + seen = seen || new Set() + if (seen.has(value)) { return value } seen.add(value) diff --git a/packages/runtime-core/src/directives.ts b/packages/runtime-core/src/directives.ts index a82a9c7dec5..58e56df0522 100644 --- a/packages/runtime-core/src/directives.ts +++ b/packages/runtime-core/src/directives.ts @@ -20,6 +20,7 @@ import { callWithAsyncErrorHandling, ErrorCodes } from './errorHandling' import { ComponentPublicInstance } from './componentPublicInstance' import { mapCompatDirectiveHook } from './compat/customDirective' import { pauseTracking, resetTracking } from '@vue/reactivity' +import { traverse } from './apiWatch' export interface DirectiveBinding { instance: ComponentPublicInstance | null @@ -51,6 +52,7 @@ export interface ObjectDirective { beforeUnmount?: DirectiveHook unmounted?: DirectiveHook getSSRProps?: SSRDirectiveHook + deep?: boolean } export type FunctionDirective = DirectiveHook @@ -101,6 +103,9 @@ export function withDirectives( updated: dir } as ObjectDirective } + if (dir.deep) { + traverse(value) + } bindings.push({ dir, instance, diff --git a/packages/runtime-dom/src/directives/vModel.ts b/packages/runtime-dom/src/directives/vModel.ts index f63f909b3c6..d721e2f3715 100644 --- a/packages/runtime-dom/src/directives/vModel.ts +++ b/packages/runtime-dom/src/directives/vModel.ts @@ -99,6 +99,8 @@ export const vModelText: ModelDirective< } export const vModelCheckbox: ModelDirective = { + // #4096 array checkboxes need to be deep traversed + deep: true, created(el, _, vnode) { el._assign = getModelAssigner(vnode) addEventListener(el, 'change', () => { @@ -171,6 +173,8 @@ export const vModelRadio: ModelDirective = { } export const vModelSelect: ModelDirective = { + //