Created
October 31, 2024 08:36
-
-
Save janeklb/dd6ac02a03efbaeccec59eb6890836d1 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* eslint-disable no-console */ | |
import { useEffect } from 'react'; | |
type ShouldLog = (name: string) => boolean; | |
type Stats = { | |
readonly name: string; | |
count: number; | |
previousState?: unknown; | |
}; | |
function stringify(input: unknown): string { | |
return typeof input === 'function' ? '[fn]' : JSON.stringify(input); | |
} | |
export class ChangeDetector { | |
private readonly statsMap = new Map<string, Stats>(); | |
constructor( | |
private readonly label: string, | |
private readonly shouldLog?: ShouldLog, | |
) {} | |
protected getStats(name: string): Stats { | |
let stats = this.statsMap.get(name); | |
if (!stats) { | |
stats = { name, count: 0 }; | |
this.statsMap.set(name, stats); | |
} | |
return stats; | |
} | |
public tick(name: string, state?: unknown): void { | |
const stats = this.getStats(name); | |
if (!this.shouldLog || this.shouldLog(name)) { | |
this.logStats(state, stats); | |
} | |
stats.previousState = state; | |
stats.count++; | |
} | |
private logStats(state: unknown, { name, count, previousState }: Stats): void { | |
const currJson = stringify(state); | |
if (count === 0) { | |
console.debug(`[${this.label}] ${name} (initialized)`, count, { curr: currJson }); | |
} else if (state === previousState) { | |
console.log(`[${this.label}] ${name} ✅ (not changed)`, count, { curr: currJson }); | |
} else { | |
const prevJson = stringify(previousState); | |
if (prevJson === currJson) { | |
console.log(`[${this.label}] ${name} ❗️ (changed, but stringified equal)`, count, { curr: currJson }); | |
} else { | |
console.log(`[${this.label}] ${name} 🔀 (changed)`, count, { prev: prevJson, curr: currJson }); | |
} | |
} | |
} | |
} | |
export function createEffectChangeLogger(label: string, shouldLog?: ShouldLog) { | |
const changeDetector = new ChangeDetector(label, shouldLog); | |
return function useEffectChangeLogger(name: string, state: unknown) { | |
useEffect(() => changeDetector.tick(name, state), [name, state]); | |
useEffect(() => () => console.log('unmounting', name), [name]); | |
}; | |
} | |
export const useGlobalEffectChangeLogger = createEffectChangeLogger('global'); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment