Skip to content

Commit ffc1ae3

Browse files
MetRonnieantfu
andauthored
fix(computedWithControl): allow deeply watching source (#4786)
Co-authored-by: Anthony Fu <anthonyfu117@hotmail.com>
1 parent 2c91ad8 commit ffc1ae3

File tree

3 files changed

+47
-11
lines changed

3 files changed

+47
-11
lines changed

packages/shared/computedWithControl/index.md

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,17 @@ const computedRef = computedWithControl(
4848
computedRef.trigger()
4949
```
5050

51-
::: warning
52-
Manual triggering only works for Vue 3
53-
:::
51+
### Deep Watch
52+
53+
Unlike `computed`, `computedWithControl` is shallow by default.
54+
You can specify the same options as `watch` to control the behavior:
55+
56+
```ts
57+
const source = ref({ name: 'foo' })
58+
59+
const computedRef = computedWithControl(
60+
source,
61+
() => counter.value,
62+
{ deep: true },
63+
)
64+
```

packages/shared/computedWithControl/index.test.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { describe, expect, it } from 'vitest'
2-
import { shallowRef } from 'vue'
2+
import { ref as deepRef, shallowRef } from 'vue'
33
import { computedWithControl, controlledComputed } from './index'
44

55
describe('computedWithControl', () => {
@@ -84,4 +84,28 @@ describe('computedWithControl', () => {
8484

8585
expect(data.value).toBe('BAZ')
8686
})
87+
88+
it('shallow watches by default', () => {
89+
const trigger = deepRef({ a: 1 })
90+
91+
const computed = computedWithControl(trigger, () => trigger.value.a)
92+
93+
expect(computed.value).toBe(1)
94+
95+
trigger.value.a = 42
96+
97+
expect(computed.value).toBe(1)
98+
})
99+
100+
it('can deep watch if specified', () => {
101+
const trigger = deepRef({ a: 1 })
102+
103+
const computed = computedWithControl(trigger, () => trigger.value.a, { deep: true })
104+
105+
expect(computed.value).toBe(1)
106+
107+
trigger.value.a = 42
108+
109+
expect(computed.value).toBe(42)
110+
})
87111
})

packages/shared/computedWithControl/index.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { ComputedGetter, ComputedRef, WatchSource, WritableComputedOptions, WritableComputedRef } from 'vue'
1+
import type { ComputedGetter, ComputedRef, WatchOptions, WatchSource, WritableComputedOptions, WritableComputedRef } from 'vue'
22
import type { Fn } from '../utils'
33
import { customRef, watch } from 'vue'
44

@@ -16,12 +16,14 @@ export type ComputedWithControlRef<T = any> = ComputedRefWithControl<T> | Writab
1616

1717
export function computedWithControl<T, S>(
1818
source: WatchSource<S> | WatchSource<S>[],
19-
fn: ComputedGetter<T>
19+
fn: ComputedGetter<T>,
20+
options?: WatchOptions
2021
): ComputedRefWithControl<T>
2122

2223
export function computedWithControl<T, S>(
2324
source: WatchSource<S> | WatchSource<S>[],
24-
fn: WritableComputedOptions<T>
25+
fn: WritableComputedOptions<T>,
26+
options?: WatchOptions
2527
): WritableComputedRefWithControl<T>
2628

2729
/**
@@ -33,6 +35,7 @@ export function computedWithControl<T, S>(
3335
export function computedWithControl<T, S>(
3436
source: WatchSource<S> | WatchSource<S>[],
3537
fn: ComputedGetter<T> | WritableComputedOptions<T>,
38+
options: WatchOptions = {},
3639
): ComputedWithControlRef<T> {
3740
let v: T = undefined!
3841
let track: Fn
@@ -44,7 +47,7 @@ export function computedWithControl<T, S>(
4447
trigger()
4548
}
4649

47-
watch(source, update, { flush: 'sync' })
50+
watch(source, update, { flush: 'sync', ...options })
4851

4952
const get = typeof fn === 'function' ? fn : fn.get
5053
const set = typeof fn === 'function' ? undefined : fn.set
@@ -68,9 +71,7 @@ export function computedWithControl<T, S>(
6871
}
6972
}) as ComputedRefWithControl<T>
7073

71-
if (Object.isExtensible(result))
72-
result.trigger = update
73-
74+
result.trigger = update
7475
return result
7576
}
7677

0 commit comments

Comments
 (0)