From 8c27d8069574dc0e43a0c62aeb98245f83aef900 Mon Sep 17 00:00:00 2001 From: ygj6 Date: Wed, 19 May 2021 17:26:14 +0800 Subject: [PATCH] feat: add and delete object attributes would trigger update. (#692) --- src/utils/instance.ts | 17 ++++++++++++++--- test/setup.spec.js | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/src/utils/instance.ts b/src/utils/instance.ts index 3ee24edc..5fa4e4b7 100644 --- a/src/utils/instance.ts +++ b/src/utils/instance.ts @@ -1,7 +1,7 @@ import { ComponentInstance } from '../component' import vmStateManager from './vmStateManager' import { setCurrentInstance, getCurrentVue2Instance } from '../runtimeContext' -import { Ref, isRef } from '../apis' +import { Ref, isRef, isReactive } from '../apis' import { hasOwn, proxy, warn } from './utils' import { createSlotProxy, resolveSlots } from './helper' @@ -20,8 +20,19 @@ export function asVmProperty( }, }) } else { - // @ts-ignore - vm[propName] = propValue + Object.defineProperty(vm, propName, { + enumerable: true, + configurable: true, + get: () => { + if (isReactive(propValue)) { + ;(propValue as any).__ob__.dep.depend() + } + return propValue + }, + set: (val) => { + propValue = val + }, + }) } if (__DEV__) { diff --git a/test/setup.spec.js b/test/setup.spec.js index 35329849..2bcbe442 100644 --- a/test/setup.spec.js +++ b/test/setup.spec.js @@ -13,6 +13,8 @@ const { isReactive, defineComponent, onMounted, + set, + del, } = require('../src') const { sleep } = require('./helpers/utils') @@ -896,6 +898,42 @@ describe('setup', () => { expect(vm.$el.textContent).toBe('2') }) + // #683 #603 #580 + it('should update directly when adding attributes to a reactive object', async () => { + const vm = new Vue({ + template: '
', + setup() { + const obj = reactive({}) + const add = () => { + set(obj, 'a', 'new property') + } + return { obj, add } + }, + }).$mount() + + expect(vm.$el.textContent).toBe('') + await vm.$el.querySelector('button').click() + expect(vm.$el.textContent).toBe('new property') + }) + + // #683 #603 #580 + it('should update directly when deleting attributes from a reactive object', async () => { + const vm = new Vue({ + template: '
', + setup() { + const obj = reactive({ a: 'hello' }) + const deleting = () => { + del(obj, 'a') + } + return { obj, deleting } + }, + }).$mount() + + expect(vm.$el.textContent).toBe('hello') + await vm.$el.querySelector('button').click() + expect(vm.$el.textContent).toBe('') + }) + // #524 it('should work with reactive arrays.', async () => { const opts = {