perf(reactivity): ref should not trigger if value did not change
Note: shallowRef will always trigger on assignment because it does not account for deep mutations close #1012
This commit is contained in:
parent
7d858a9001
commit
b0d4df9743
@ -22,11 +22,19 @@ describe('reactivity/ref', () => {
|
|||||||
it('should be reactive', () => {
|
it('should be reactive', () => {
|
||||||
const a = ref(1)
|
const a = ref(1)
|
||||||
let dummy
|
let dummy
|
||||||
|
let calls = 0
|
||||||
effect(() => {
|
effect(() => {
|
||||||
|
calls++
|
||||||
dummy = a.value
|
dummy = a.value
|
||||||
})
|
})
|
||||||
|
expect(calls).toBe(1)
|
||||||
expect(dummy).toBe(1)
|
expect(dummy).toBe(1)
|
||||||
a.value = 2
|
a.value = 2
|
||||||
|
expect(calls).toBe(2)
|
||||||
|
expect(dummy).toBe(2)
|
||||||
|
// same value should not trigger
|
||||||
|
a.value = 2
|
||||||
|
expect(calls).toBe(2)
|
||||||
expect(dummy).toBe(2)
|
expect(dummy).toBe(2)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -174,6 +182,22 @@ describe('reactivity/ref', () => {
|
|||||||
expect(dummy).toBe(2)
|
expect(dummy).toBe(2)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('shallowRef force trigger', () => {
|
||||||
|
const sref = shallowRef({ a: 1 })
|
||||||
|
let dummy
|
||||||
|
effect(() => {
|
||||||
|
dummy = sref.value.a
|
||||||
|
})
|
||||||
|
expect(dummy).toBe(1)
|
||||||
|
|
||||||
|
sref.value.a = 2
|
||||||
|
expect(dummy).toBe(1) // should not trigger yet
|
||||||
|
|
||||||
|
// force trigger
|
||||||
|
sref.value = sref.value
|
||||||
|
expect(dummy).toBe(2)
|
||||||
|
})
|
||||||
|
|
||||||
test('isRef', () => {
|
test('isRef', () => {
|
||||||
expect(isRef(ref(1))).toBe(true)
|
expect(isRef(ref(1))).toBe(true)
|
||||||
expect(isRef(computed(() => 1))).toBe(true)
|
expect(isRef(computed(() => 1))).toBe(true)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { track, trigger } from './effect'
|
import { track, trigger } from './effect'
|
||||||
import { TrackOpTypes, TriggerOpTypes } from './operations'
|
import { TrackOpTypes, TriggerOpTypes } from './operations'
|
||||||
import { isObject } from '@vue/shared'
|
import { isObject, hasChanged } from '@vue/shared'
|
||||||
import { reactive, isProxy } from './reactive'
|
import { reactive, isProxy, toRaw } from './reactive'
|
||||||
import { ComputedRef } from './computed'
|
import { ComputedRef } from './computed'
|
||||||
import { CollectionTypes } from './collectionHandlers'
|
import { CollectionTypes } from './collectionHandlers'
|
||||||
|
|
||||||
@ -43,13 +43,11 @@ export function shallowRef(value?: unknown) {
|
|||||||
return createRef(value, true)
|
return createRef(value, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
function createRef(value: unknown, shallow = false) {
|
function createRef(rawValue: unknown, shallow = false) {
|
||||||
if (isRef(value)) {
|
if (isRef(rawValue)) {
|
||||||
return value
|
return rawValue
|
||||||
}
|
|
||||||
if (!shallow) {
|
|
||||||
value = convert(value)
|
|
||||||
}
|
}
|
||||||
|
let value = shallow ? rawValue : convert(rawValue)
|
||||||
const r = {
|
const r = {
|
||||||
_isRef: true,
|
_isRef: true,
|
||||||
get value() {
|
get value() {
|
||||||
@ -57,13 +55,16 @@ function createRef(value: unknown, shallow = false) {
|
|||||||
return value
|
return value
|
||||||
},
|
},
|
||||||
set value(newVal) {
|
set value(newVal) {
|
||||||
value = shallow ? newVal : convert(newVal)
|
if (shallow || hasChanged(toRaw(newVal), rawValue)) {
|
||||||
trigger(
|
rawValue = newVal
|
||||||
r,
|
value = shallow ? newVal : convert(newVal)
|
||||||
TriggerOpTypes.SET,
|
trigger(
|
||||||
'value',
|
r,
|
||||||
__DEV__ ? { newValue: newVal } : void 0
|
TriggerOpTypes.SET,
|
||||||
)
|
'value',
|
||||||
|
__DEV__ ? { newValue: newVal } : void 0
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return r
|
return r
|
||||||
|
Loading…
Reference in New Issue
Block a user