fix(reactivity): account for NaN in value change checks (#361)

This commit is contained in:
Mayness 2019-10-23 10:53:43 -05:00 committed by Evan You
parent 11d0778f9c
commit 18a349ce8c
7 changed files with 47 additions and 8 deletions

View File

@ -311,5 +311,13 @@ describe('reactivity/collections', () => {
map.get(key)!.foo++
expect(dummy).toBe(2)
})
it('should not be trigger when the value and the old value both are NaN', () => {
const map = reactive(new Map([['foo', NaN]]))
const mapSpy = jest.fn(() => map.get('foo'))
effect(mapSpy)
map.set('foo', NaN)
expect(mapSpy).toHaveBeenCalledTimes(1)
})
})
})

View File

@ -107,5 +107,15 @@ describe('reactivity/collections', () => {
observed.get(key).a = 2
expect(dummy).toBe(2)
})
it('should not be trigger when the value and the old value both are NaN', () => {
const map = new WeakMap()
const key = {}
map.set(key, NaN)
const mapSpy = jest.fn(() => map.get(key))
effect(mapSpy)
map.set(key, NaN)
expect(mapSpy).toHaveBeenCalledTimes(1)
})
})
})

View File

@ -691,4 +691,14 @@ describe('reactivity/effect', () => {
obj.foo = { prop: 1 }
expect(dummy).toBe(1)
})
it('should not be trigger when the value and the old value both are NaN', () => {
const obj = reactive({
foo: NaN
})
const fnSpy = jest.fn(() => obj.foo)
effect(fnSpy)
obj.foo = NaN
expect(fnSpy).toHaveBeenCalledTimes(1)
})
})

View File

@ -2,7 +2,7 @@ import { reactive, readonly, toRaw } from './reactive'
import { OperationTypes } from './operations'
import { track, trigger } from './effect'
import { LOCKED } from './lock'
import { isObject, hasOwn, isSymbol } from '@vue/shared'
import { isObject, hasOwn, isSymbol, hasChanged } from '@vue/shared'
import { isRef } from './ref'
const builtInSymbols = new Set(
@ -52,13 +52,13 @@ function set(
const extraInfo = { oldValue, newValue: value }
if (!hadKey) {
trigger(target, OperationTypes.ADD, key, extraInfo)
} else if (value !== oldValue) {
} else if (hasChanged(value, oldValue)) {
trigger(target, OperationTypes.SET, key, extraInfo)
}
} else {
if (!hadKey) {
trigger(target, OperationTypes.ADD, key)
} else if (value !== oldValue) {
} else if (hasChanged(value, oldValue)) {
trigger(target, OperationTypes.SET, key)
}
}

View File

@ -2,7 +2,7 @@ import { toRaw, reactive, readonly } from './reactive'
import { track, trigger } from './effect'
import { OperationTypes } from './operations'
import { LOCKED } from './lock'
import { isObject, capitalize, hasOwn } from '@vue/shared'
import { isObject, capitalize, hasOwn, hasChanged } from '@vue/shared'
export type CollectionTypes = IterableCollections | WeakCollections
@ -73,13 +73,13 @@ function set(this: MapTypes, key: unknown, value: unknown) {
const extraInfo = { oldValue, newValue: value }
if (!hadKey) {
trigger(target, OperationTypes.ADD, key, extraInfo)
} else if (value !== oldValue) {
} else if (hasChanged(value, oldValue)) {
trigger(target, OperationTypes.SET, key, extraInfo)
}
} else {
if (!hadKey) {
trigger(target, OperationTypes.ADD, key)
} else if (value !== oldValue) {
} else if (hasChanged(value, oldValue)) {
trigger(target, OperationTypes.SET, key)
}
}

View File

@ -7,7 +7,14 @@ import {
ReactiveEffectOptions
} from '@vue/reactivity'
import { queueJob } from './scheduler'
import { EMPTY_OBJ, isObject, isArray, isFunction, isString } from '@vue/shared'
import {
EMPTY_OBJ,
isObject,
isArray,
isFunction,
isString,
hasChanged
} from '@vue/shared'
import { recordEffect } from './apiReactivity'
import {
currentInstance,
@ -144,7 +151,7 @@ function doWatch(
return
}
const newValue = runner()
if (deep || newValue !== oldValue) {
if (deep || hasChanged(newValue, oldValue)) {
// cleanup before running cb again
if (cleanup) {
cleanup()

View File

@ -67,3 +67,7 @@ export const hyphenate = (str: string): string => {
export const capitalize = (str: string): string => {
return str.charAt(0).toUpperCase() + str.slice(1)
}
// compare whether a value has changed, accounting for NaN.
export const hasChanged = (value: any, oldValue: any): boolean =>
value !== oldValue && (value === value || oldValue === oldValue)