diff --git a/hooks/src/index.js b/hooks/src/index.js index 56f1aa11d3..8606dbcc11 100644 --- a/hooks/src/index.js +++ b/hooks/src/index.js @@ -236,7 +236,7 @@ export function useReducer(reducer, initialState, init) { const currentValue = hookItem._value[0]; hookItem._value = hookItem._nextValue; hookItem._nextValue = undefined; - if (currentValue !== hookItem._value[0]) shouldUpdate = true; + if (!is(currentValue, hookItem._value[0])) shouldUpdate = true; } }); @@ -493,6 +493,16 @@ function invokeEffect(hook) { currentComponent = comp; } +/** + * Check if two values are the same value + * @param {*} x + * @param {*} y + * @returns {boolean} + */ +function is(x, y) { + return (x === y && (x !== 0 || 1 / x === 1 / y)) || (x !== x && y !== y); +} + /** * @param {any[]} oldArgs * @param {any[]} newArgs diff --git a/hooks/test/browser/useState.test.js b/hooks/test/browser/useState.test.js index 58b152afc8..bcd30840a1 100644 --- a/hooks/test/browser/useState.test.js +++ b/hooks/test/browser/useState.test.js @@ -371,4 +371,30 @@ describe('useState', () => { rerender(); expect(scratch.innerHTML).to.equal('
hello world!!!
'); }); + + it('should limit rerenders when setting state to NaN', () => { + const calls = []; + const App = ({ i }) => { + calls.push('rendering' + i); + const [greeting, setGreeting] = useState(0); + + if (i === 2) { + setGreeting(NaN); + } + + return{greeting}
; + }; + + act(() => { + render(