UNPKG

react-smart-effect

Version:

Enhanced React useEffect and useLayoutEffect hooks with smart dependency tracking, debugging tools, and automatic optimization

145 lines (144 loc) 5.38 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.deepCompareDeps = deepCompareDeps; exports.analyzeDeps = analyzeDeps; exports.generateDependencyWarning = generateDependencyWarning; exports.logDependencyChanges = logDependencyChanges; exports.createEffectId = createEffectId; exports.formatDependencyValue = formatDependencyValue; const lodash_isequal_1 = __importDefault(require("lodash.isequal")); /** * Deep comparison function for dependency arrays */ function deepCompareDeps(prevDeps, nextDeps) { if (!prevDeps || !nextDeps) return prevDeps === nextDeps; if (prevDeps.length !== nextDeps.length) return false; return prevDeps.every((prev, index) => { const next = nextDeps[index]; if (typeof prev === 'object' && prev !== null) { return (0, lodash_isequal_1.default)(prev, next); } return Object.is(prev, next); }); } /** * Analyzes dependencies to categorize them and detect potential issues */ function analyzeDeps(deps) { const analysis = { primitives: [], objects: [], functions: [], potentiallyMissing: [], redundant: [] }; deps.forEach((dep, index) => { const type = typeof dep; switch (type) { case 'string': case 'number': case 'boolean': case 'undefined': analysis.primitives.push(dep); break; case 'function': analysis.functions.push(dep); // More precise anonymous function detection const fnString = dep.toString().trim(); // Check if it's truly an anonymous function by examining the source const isAnonymous = // Arrow functions are generally considered anonymous in this context fnString.includes('=>') || // Function expressions without names /^function\s*\(/.test(fnString) || // Functions with empty or 'anonymous' names !dep.name || dep.name === 'anonymous'; analysis.potentiallyMissing.push(isAnonymous ? `Anonymous function at index ${index}` : `Named function at index ${index}`); break; case 'object': if (dep === null) { analysis.primitives.push(dep); } else if (Array.isArray(dep)) { analysis.objects.push(dep); analysis.potentiallyMissing.push(`Array at index ${index}`); } else { analysis.objects.push(dep); analysis.potentiallyMissing.push(`Object at index ${index}`); } break; } }); return analysis; } /** * Generates a warning message for dependency analysis */ function generateDependencyWarning(analysis, effectId) { const warnings = []; if (analysis.potentiallyMissing.length > 0) { warnings.push(`Potentially unstable dependencies detected:\n${analysis.potentiallyMissing .map(msg => ` - ${msg}`) .join('\n')}`); } if (analysis.functions.length > 0) { warnings.push(`Function dependencies detected (${analysis.functions.length}). Consider wrapping with useCallback.`); } if (analysis.objects.length > 0) { warnings.push(`Object/Array dependencies detected (${analysis.objects.length}). Consider wrapping with useMemo or enable deepCompare.`); } if (warnings.length === 0) return null; const prefix = effectId ? `[useSmartEffect:${effectId}]` : '[useSmartEffect]'; return `${prefix} Dependency Analysis:\n${warnings.join('\n\n')}`; } /** * Logs dependency changes for debugging */ function logDependencyChanges(prevDeps, nextDeps, effectId) { if (!prevDeps || !nextDeps) return; const changes = nextDeps .map((next, index) => { const prev = prevDeps[index]; const changed = !Object.is(prev, next) && !(0, lodash_isequal_1.default)(prev, next); return { index, prev, next, changed }; }) .filter(c => c.changed); if (changes.length > 0) { const prefix = effectId ? `[useSmartEffect:${effectId}]` : '[useSmartEffect]'; console.group(`${prefix} Dependencies Changed`); changes.forEach(({ index, prev, next }) => console.log(`Index ${index}:`, { prev, next })); console.groupEnd(); } } /** * Creates a unique identifier for an effect */ function createEffectId() { return `effect_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; } /** * Formats dependency values for display */ function formatDependencyValue(value) { if (value === null) return 'null'; if (value === undefined) return 'undefined'; if (typeof value === 'function') return `[Function ${value.name || 'anonymous'}]`; if (typeof value === 'object') { if (Array.isArray(value)) return `Array(${value.length})`; return `Object(${Object.keys(value).length} keys)`; } return String(value); }