declare const RefSymbol: unique symbol
export interface Ref<T = any> {
+ value: T
/**
* Type differentiator only.
* We need this to be in public d.ts but don't want it to show up in IDE
* autocomplete, so we use a private Symbol instead.
*/
[RefSymbol]: true
- value: T
+ /**
+ * @internal
+ */
+ _shallow?: boolean
}
export type ToRefs<T = any> = { [K in keyof T]: Ref<T[K]> }
public readonly __v_isRef = true
- constructor(private _rawValue: T, private readonly _shallow = false) {
+ constructor(private _rawValue: T, public readonly _shallow = false) {
this._value = _shallow ? _rawValue : convert(_rawValue)
}
}
export function triggerRef(ref: Ref) {
- trigger(ref, TriggerOpTypes.SET, 'value', __DEV__ ? ref.value : void 0)
+ trigger(toRaw(ref), TriggerOpTypes.SET, 'value', __DEV__ ? ref.value : void 0)
}
export function unref<T>(ref: T): T extends Ref<infer V> ? V : T {
DebuggerEvent,
TrackOpTypes,
TriggerOpTypes,
- triggerRef
+ triggerRef,
+ shallowRef
} from '@vue/reactivity'
// reference: https://vue-composition-api-rfc.netlify.com/api.html#watch
expect(calls).toBe(1)
})
- test('should force trigger on triggerRef when watching a ref', async () => {
- const v = ref({ a: 1 })
+ test('should force trigger on triggerRef when watching a shallow ref', async () => {
+ const v = shallowRef({ a: 1 })
let sideEffect = 0
watch(v, obj => {
sideEffect = obj.a
await nextTick()
expect(spy).toHaveBeenCalledTimes(1)
})
+
+ // #2231
+ test('computed refs should not trigger watch if value has no change', async () => {
+ const spy = jest.fn()
+ const source = ref(0)
+ const price = computed(() => source.value === 0)
+ watch(price, spy)
+ source.value++
+ await nextTick()
+ source.value++
+ await nextTick()
+ expect(spy).toHaveBeenCalledTimes(1)
+ })
})
}
let getter: () => any
- const isRefSource = isRef(source)
- if (isRefSource) {
+ let forceTrigger = false
+ if (isRef(source)) {
getter = () => (source as Ref).value
+ forceTrigger = !!(source as Ref)._shallow
} else if (isReactive(source)) {
getter = () => source
deep = true
if (cb) {
// watch(source, cb)
const newValue = runner()
- if (deep || isRefSource || hasChanged(newValue, oldValue)) {
+ if (deep || forceTrigger || hasChanged(newValue, oldValue)) {
// cleanup before running cb again
if (cleanup) {
cleanup()