Skip to content

Commit 189483b

Browse files
authored
Merge pull request #11 from aljadan/main
Implement deep equality check for line chart props comparison
2 parents 907fe25 + ee08815 commit 189483b

4 files changed

Lines changed: 105 additions & 15 deletions

File tree

example/App.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
/* eslint-disable no-restricted-exports */
22
import 'react-native-gesture-handler';
33

4-
export {default} from './src/App2';
4+
export {default} from './src/App';

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-native-simple-line-chart",
3-
"version": "0.37.0",
3+
"version": "0.37.1",
44
"description": "A fast, interactive, animated and simple line chart component for React Native",
55
"main": "lib/commonjs/index",
66
"module": "lib/module/index",

src/LineChart.tsx

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
LineChart as LineChartProps,
1616
LineChartRef,
1717
} from './types';
18+
import { isEqual } from './utils';
1819

1920
const getExtraConfig = (extraConfig: ExtraConfig): ExtraConfig => {
2021
return {
@@ -221,23 +222,13 @@ export const MemoizedLineChart = React.memo(
221222
return false;
222223
}
223224

224-
if (
225-
JSON.stringify(previousProps.lines[previousProps.activeLineIndex || 0]) !==
226-
JSON.stringify(nextProps.lines[nextProps.activeLineIndex || 0])
227-
) {
228-
return false;
229-
}
230-
231-
if (
232-
JSON.stringify(previousProps.lines[1]?.data) !==
233-
JSON.stringify(nextProps.lines[1]?.data)
234-
) {
225+
if (!isEqual(previousProps.lines, nextProps.lines)) {
235226
return false;
236227
}
237228

238229
if (
239-
JSON.stringify(previousProps.backgroundColor) !==
240-
JSON.stringify(nextProps.backgroundColor)
230+
previousProps.backgroundColor !==
231+
nextProps.backgroundColor
241232
) {
242233
return false;
243234
}

src/utils.ts

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,3 +248,102 @@ export const useForceReRender = () => {
248248

249249
return forceUpdate;
250250
};
251+
252+
/**
253+
* Fast deep equality comparison function
254+
* Based on fast-deep-equal library
255+
* Note: Functions are treated as equal without deep comparison
256+
*/
257+
export function isEqual(a: any, b: any): boolean {
258+
if (a === b) return true;
259+
260+
// Ignore function checks - return them as equal
261+
if (typeof a === 'function' && typeof b === 'function') return true;
262+
263+
if (a && b && typeof a === 'object' && typeof b === 'object') {
264+
if (a.constructor !== b.constructor) return false;
265+
266+
let length: number;
267+
let i: any;
268+
let keys: string[];
269+
270+
if (Array.isArray(a)) {
271+
length = a.length;
272+
if (length !== b.length) return false;
273+
for (i = length; i-- !== 0; ) {
274+
if (!isEqual(a[i], b[i])) return false;
275+
}
276+
return true;
277+
}
278+
279+
if (a instanceof Map && b instanceof Map) {
280+
if (a.size !== b.size) return false;
281+
for (i of a.entries()) {
282+
if (!b.has(i[0])) return false;
283+
}
284+
for (i of a.entries()) {
285+
if (!isEqual(i[1], b.get(i[0]))) return false;
286+
}
287+
return true;
288+
}
289+
290+
if (a instanceof Set && b instanceof Set) {
291+
if (a.size !== b.size) return false;
292+
for (i of a.entries()) {
293+
if (!b.has(i[0])) return false;
294+
}
295+
return true;
296+
}
297+
298+
if (ArrayBuffer.isView(a) && ArrayBuffer.isView(b)) {
299+
const aView = a as any;
300+
const bView = b as any;
301+
length = aView.length;
302+
if (length !== bView.length) return false;
303+
for (i = length; i-- !== 0; ) {
304+
if (aView[i] !== bView[i]) return false;
305+
}
306+
return true;
307+
}
308+
309+
if (a.constructor === RegExp) {
310+
return a.source === b.source && a.flags === b.flags;
311+
}
312+
313+
if (a.valueOf !== Object.prototype.valueOf) {
314+
return a.valueOf() === b.valueOf();
315+
}
316+
317+
if (a.toString !== Object.prototype.toString) {
318+
return a.toString() === b.toString();
319+
}
320+
321+
keys = Object.keys(a);
322+
length = keys.length;
323+
if (length !== Object.keys(b).length) return false;
324+
325+
for (i = length; i-- !== 0; ) {
326+
const key = keys[i];
327+
if (key !== undefined && !Object.prototype.hasOwnProperty.call(b, key)) return false;
328+
}
329+
330+
for (i = length; i-- !== 0; ) {
331+
const key = keys[i];
332+
if (key === undefined) continue;
333+
334+
// React-specific: avoid traversing React elements' _owner
335+
// _owner contains circular references and is not needed when comparing actual elements
336+
if (key === '_owner' && a.$$typeof) {
337+
continue;
338+
}
339+
340+
if (!isEqual(a[key], b[key])) return false;
341+
}
342+
343+
return true;
344+
}
345+
346+
// true if both NaN, false otherwise
347+
return a !== a && b !== b;
348+
}
349+

0 commit comments

Comments
 (0)