From a46ba650e6d56069cd3a78dd16ca83ede6da5a24 Mon Sep 17 00:00:00 2001 From: "moxey.eth" Date: Mon, 6 Jun 2022 15:39:17 +1000 Subject: [PATCH] fix: `replaceDeepEqual` special case for non-plain arrays (#3669) * Fix case where replaceDeepEqual was returning incorrect value for non-plain arrays * fix pr comments --- src/core/tests/utils.test.tsx | 18 ++++++++++++++++++ src/core/utils.ts | 6 +++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/core/tests/utils.test.tsx b/src/core/tests/utils.test.tsx index 1a0b8dd0db..6e00a9db00 100644 --- a/src/core/tests/utils.test.tsx +++ b/src/core/tests/utils.test.tsx @@ -6,6 +6,7 @@ import { matchMutation, scheduleMicrotask, sleep, + isPlainArray, } from '../utils' import { Mutation } from '../mutation' import { createQueryClient } from '../../tests/utils' @@ -56,6 +57,16 @@ describe('core/utils', () => { }) }) + describe('isPlainArray', () => { + it('should return `true` for plain arrays', () => { + expect(isPlainArray([1, 2])).toEqual(true) + }) + + it('should return `false` for non plain arrays', () => { + expect(isPlainArray(Object.assign([1, 2], { a: 'b' }))).toEqual(false) + }) + }) + describe('partialDeepEqual', () => { it('should return `true` if a includes b', () => { const a = { a: { b: 'b' }, c: 'c', d: [{ d: 'd ' }] } @@ -258,6 +269,13 @@ describe('core/utils', () => { expect(result[1]).toBe(prev[1]) }) + it('should support objects which are not plain arrays', () => { + const prev = Object.assign([1, 2], { a: { b: 'b' }, c: 'c' }) + const next = Object.assign([1, 2], { a: { b: 'b' }, c: 'c' }) + const result = replaceEqualDeep(prev, next) + expect(result).toBe(next) + }) + it('should replace all parent objects if some nested value changes', () => { const prev = { todo: { id: '1', meta: { createdAt: 0 }, state: { done: false } }, diff --git a/src/core/utils.ts b/src/core/utils.ts index 8fdb107b54..cdec3d83f4 100644 --- a/src/core/utils.ts +++ b/src/core/utils.ts @@ -314,7 +314,7 @@ export function replaceEqualDeep(a: any, b: any): any { return a } - const array = Array.isArray(a) && Array.isArray(b) + const array = isPlainArray(a) && isPlainArray(b) if (array || (isPlainObject(a) && isPlainObject(b))) { const aSize = array ? a.length : Object.keys(a).length @@ -355,6 +355,10 @@ export function shallowEqualObjects(a: T, b: T): boolean { return true } +export function isPlainArray(value: unknown) { + return Array.isArray(value) && value.length === Object.keys(value).length +} + // Copied from: https://github.com/jonschlinkert/is-plain-object export function isPlainObject(o: any): o is Object { if (!hasObjectPrototype(o)) {