All files / src/features/transaction/utils memo-utils.ts

81.81% Statements 36/44
80% Branches 24/30
77.77% Functions 7/9
85% Lines 34/40

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123                        5x 7x 2x   2x               2x             5x 1x   1x         1x         1x 1x 1x     2x 2x   1x 1x     1x 2x 2x 2x   2x 1x         1x                     1x                       5x   5x 1x       4x 1x       3x 1x       2x       1x     1x                
import isEqual from 'react-fast-compare';
 
/**
 * Utility functions for deep comparison and memoization
 * to improve React rendering performance
 */
 
/**
 * Creates a memoization-friendly comparison function for React.memo
 * Uses react-fast-compare for deep equality checks
 * @returns A function that can be used in React.memo to determine if props are equal
 */
export const createDeepEqualityFn = <T>() => {
  return (prevProps: T, nextProps: T): boolean => {
    const areEqual = isEqual(prevProps, nextProps);
 
    console.log('🔍 Deep equality check:', {
      areEqual,
      prevProps,
      nextProps,
      differences: areEqual ? 'None' : detectDifferences(prevProps, nextProps),
      timestamp: new Date().toISOString(),
    });
 
    return areEqual;
  };
};
 
/**
 * Helper function to detect and log specific differences between objects
 */
const detectDifferences = <T>(prev: T, next: T): string[] => {
  const differences: string[] = [];
 
  Iif (typeof prev !== typeof next) {
    differences.push(`Type changed: ${typeof prev} → ${typeof next}`);
    return differences;
  }
 
  Iif (prev === null || next === null) {
    differences.push(`Null check: ${prev} → ${next}`);
    return differences;
  }
 
  if (typeof prev === 'object' && typeof next === 'object') {
    const prevKeys = Object.keys(prev as any);
    const nextKeys = Object.keys(next as any);
 
    // Check for added/removed keys
    const addedKeys = nextKeys.filter(key => !prevKeys.includes(key));
    const removedKeys = prevKeys.filter(key => !nextKeys.includes(key));
 
    addedKeys.forEach(key => differences.push(`Added key: ${key}`));
    removedKeys.forEach(key => differences.push(`Removed key: ${key}`));
 
    // Check for changed values
    prevKeys.forEach(key => {
      Eif (nextKeys.includes(key)) {
        const prevVal = (prev as any)[key];
        const nextVal = (next as any)[key];
 
        if (!isEqual(prevVal, nextVal)) {
          Iif (typeof prevVal === 'function' && typeof nextVal === 'function') {
            differences.push(
              `Function changed: ${key} (${prevVal.toString().slice(0, 50)}... → ${nextVal.toString().slice(0, 50)}...)`
            );
          } else {
            differences.push(
              `Value changed: ${key} (${JSON.stringify(prevVal)} → ${JSON.stringify(nextVal)})`
            );
          }
        }
      }
    });
  } else E{
    differences.push(`Value changed: ${prev} → ${next}`);
  }
 
  return differences;
};
 
/**
 * Determines if an array has meaningfully changed by checking:
 * 1. If array length has changed
 * 2. If first item has changed (using deep equality)
 * 3. If last item has changed (using deep equality)
 *
 * This is a more efficient approach than checking every item
 * when dealing with large arrays where most operations occur at the beginning/end
 */
export const hasArrayChanged = <T>(prevArray: T[], nextArray: T[]): boolean => {
  // Length check
  if (prevArray.length !== nextArray.length) {
    return true;
  }
 
  // Empty array check
  if (prevArray.length === 0) {
    return false;
  }
 
  // Check first item
  if (!isEqual(prevArray[0], nextArray[0])) {
    return true;
  }
 
  // Check last item for arrays with more than one item
  if (
    prevArray.length > 1 &&
    !isEqual(prevArray[prevArray.length - 1], nextArray[nextArray.length - 1])
  ) {
    return true;
  }
 
  return false;
};
 
/**
 * Re-export isEqual from react-fast-compare for consistent usage across the app
 * Use this for deep equality checks when you need to compare complex objects
 */
export { isEqual };