mirror of
https://github.com/hanzoai/sentinel.git
synced 2026-09-29 22:34:33 +00:00
67 lines
1.8 KiB
TypeScript
67 lines
1.8 KiB
TypeScript
import {useMemo, useRef} from 'react';
|
|
|
|
/**
|
|
* Check if two objects have the same keys
|
|
*/
|
|
const checkSameKeys = (obj1: any, obj2: any) => {
|
|
const keys1 = new Set(Object.keys(obj1));
|
|
const keys2 = new Set(Object.keys(obj2));
|
|
if (keys1.size !== keys2.size) {
|
|
return false;
|
|
}
|
|
for (const key in keys1) {
|
|
if (!keys2.has(key)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
};
|
|
|
|
/**
|
|
* Merge oldVlaue and newValue while trying to preserve references of unchanged objects / arrays
|
|
*/
|
|
export function structuralSharing<T>(oldValue: T, newValue: T): T {
|
|
if (oldValue === newValue) {
|
|
return oldValue;
|
|
}
|
|
|
|
if (Array.isArray(oldValue) && Array.isArray(newValue)) {
|
|
let hasChanges = oldValue.length !== newValue.length;
|
|
const newArray = newValue.map((item, index) => {
|
|
const newItem = structuralSharing(oldValue[index], item);
|
|
if (newItem !== oldValue[index]) {
|
|
hasChanges = true;
|
|
}
|
|
return newItem;
|
|
});
|
|
return hasChanges ? (newArray as any) : oldValue;
|
|
}
|
|
|
|
if (oldValue === null || newValue === null) {
|
|
return newValue;
|
|
}
|
|
|
|
if (typeof oldValue === 'object' && typeof newValue === 'object') {
|
|
let hasChanges = !checkSameKeys(oldValue, newValue);
|
|
const newObj = Object.keys(newValue).reduce((acc, key) => {
|
|
acc[key] = structuralSharing(oldValue[key], newValue[key]);
|
|
if (acc[key] !== oldValue[key]) {
|
|
hasChanges = true;
|
|
}
|
|
return acc;
|
|
}, {});
|
|
return hasChanges ? (newObj as any) : oldValue;
|
|
}
|
|
|
|
return newValue;
|
|
}
|
|
|
|
export const useStructuralSharing = (value: any) => {
|
|
const previeousValue = useRef<any>(value);
|
|
return useMemo(() => {
|
|
const newValue = structuralSharing(previeousValue.current, value);
|
|
previeousValue.current = newValue;
|
|
return newValue;
|
|
}, [value]);
|
|
};
|