Skip to content

Commit 8c27d80

Browse files
authored
feat: add and delete object attributes would trigger update. (#692)
1 parent 3485ecb commit 8c27d80

File tree

2 files changed

+52
-3
lines changed

2 files changed

+52
-3
lines changed

Diff for: src/utils/instance.ts

+14-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { ComponentInstance } from '../component'
22
import vmStateManager from './vmStateManager'
33
import { setCurrentInstance, getCurrentVue2Instance } from '../runtimeContext'
4-
import { Ref, isRef } from '../apis'
4+
import { Ref, isRef, isReactive } from '../apis'
55
import { hasOwn, proxy, warn } from './utils'
66
import { createSlotProxy, resolveSlots } from './helper'
77

@@ -20,8 +20,19 @@ export function asVmProperty(
2020
},
2121
})
2222
} else {
23-
// @ts-ignore
24-
vm[propName] = propValue
23+
Object.defineProperty(vm, propName, {
24+
enumerable: true,
25+
configurable: true,
26+
get: () => {
27+
if (isReactive(propValue)) {
28+
;(propValue as any).__ob__.dep.depend()
29+
}
30+
return propValue
31+
},
32+
set: (val) => {
33+
propValue = val
34+
},
35+
})
2536
}
2637

2738
if (__DEV__) {

Diff for: test/setup.spec.js

+38
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ const {
1313
isReactive,
1414
defineComponent,
1515
onMounted,
16+
set,
17+
del,
1618
} = require('../src')
1719
const { sleep } = require('./helpers/utils')
1820

@@ -896,6 +898,42 @@ describe('setup', () => {
896898
expect(vm.$el.textContent).toBe('2')
897899
})
898900

901+
// #683 #603 #580
902+
it('should update directly when adding attributes to a reactive object', async () => {
903+
const vm = new Vue({
904+
template: '<div><button @click="add"/>{{ obj.a }}</div>',
905+
setup() {
906+
const obj = reactive({})
907+
const add = () => {
908+
set(obj, 'a', 'new property')
909+
}
910+
return { obj, add }
911+
},
912+
}).$mount()
913+
914+
expect(vm.$el.textContent).toBe('')
915+
await vm.$el.querySelector('button').click()
916+
expect(vm.$el.textContent).toBe('new property')
917+
})
918+
919+
// #683 #603 #580
920+
it('should update directly when deleting attributes from a reactive object', async () => {
921+
const vm = new Vue({
922+
template: '<div><button @click="deleting"/>{{ obj.a }}</div>',
923+
setup() {
924+
const obj = reactive({ a: 'hello' })
925+
const deleting = () => {
926+
del(obj, 'a')
927+
}
928+
return { obj, deleting }
929+
},
930+
}).$mount()
931+
932+
expect(vm.$el.textContent).toBe('hello')
933+
await vm.$el.querySelector('button').click()
934+
expect(vm.$el.textContent).toBe('')
935+
})
936+
899937
// #524
900938
it('should work with reactive arrays.', async () => {
901939
const opts = {

0 commit comments

Comments
 (0)