Skip to content

Commit 13bfed1

Browse files
pikaxantfu
andauthored
fix(watch): watch will trigger when added new keys using set (#468)
* fix(watch): watch will trigger when added new keys using `set` * chore: add docs * Update README.md Co-authored-by: Anthony Fu <[email protected]> * Update README.md Co-authored-by: Anthony Fu <[email protected]>
1 parent f7990c9 commit 13bfed1

File tree

3 files changed

+50
-1
lines changed

3 files changed

+50
-1
lines changed

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,27 @@ a.list.push(
174174
a.list[1].count === 1 // true
175175
```
176176

177+
</details>
178+
179+
<details>
180+
<summary>
181+
⚠️ `set` workaround for adding new reactive properties
182+
</summary>
183+
184+
> ⚠️ Warning: `set` does NOT exist in Vue 3. We provide it as a workaround here, due to the limitation of [Vue 2.x reactivity system](https://vuejs.org/v2/guide/reactivity.html#For-Objects). In Vue 2, you will need to call `set` to track new keys on an `object`(similar to `Vue.set` but for `reactive objects` created by the Composition API). In Vue 3, you can just assign them like normal objects.
185+
186+
```ts
187+
import { reactive, set } from '@vue/composition-api'
188+
189+
const a = reactive({
190+
foo: 1
191+
})
192+
193+
// add new reactive key
194+
set(a, 'bar', 1)
195+
```
196+
197+
177198
</details>
178199

179200
### Template Refs

src/apis/watch.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ export interface VueWatcher {
5050
lazy: boolean
5151
get(): any
5252
teardown(): void
53+
run(): void
54+
55+
value: any
5356
}
5457

5558
export type WatchStopHandle = () => void
@@ -315,6 +318,19 @@ function createWatcher(
315318

316319
// Once again, we have to hack the watcher for proper teardown
317320
const watcher = vm._watchers[vm._watchers.length - 1]
321+
322+
// if the return value is reactive and deep:true
323+
// watch for changes, this might happen when new key is added
324+
if (isReactive(watcher.value) && deep) {
325+
watcher.value.__ob__.dep.addSub({
326+
update() {
327+
// this will force the source to be revaluated and the callback
328+
// executed if needed
329+
watcher.run()
330+
},
331+
})
332+
}
333+
318334
patchWatcherTeardown(watcher, runCleanup)
319335

320336
return () => {

test/apis/watch.spec.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
const Vue = require('vue/dist/vue.common.js')
2-
const { ref, reactive, watch, watchEffect } = require('../../src')
2+
const { ref, reactive, watch, watchEffect, set } = require('../../src')
33

44
describe('api/watch', () => {
55
const anyFn = expect.any(Function)
@@ -745,4 +745,16 @@ describe('api/watch', () => {
745745
.then(done)
746746
})
747747
})
748+
749+
it('should execute watch when new key is added', () => {
750+
const r = reactive({})
751+
752+
const cb = jest.fn()
753+
754+
watch(r, cb, { deep: true })
755+
756+
set(r, 'a', 1)
757+
758+
expect(cb).toHaveBeenCalled()
759+
})
748760
})

0 commit comments

Comments
 (0)