Skip to content

Instantly share code, notes, and snippets.

@MarekZeman91
Created April 18, 2022 00:14
Show Gist options
  • Save MarekZeman91/1bc41381b1c8e2a778763ca505ec2b7b to your computer and use it in GitHub Desktop.
Save MarekZeman91/1bc41381b1c8e2a778763ca505ec2b7b to your computer and use it in GitHub Desktop.
import { useMemo, useRef } from 'react';
export type UseValuesChangeWatcherResult<T extends Record<string, unknown>> = {
[K in keyof T]?: {
oldValue: unknown;
newValue: unknown;
};
};
const compareFn = <T extends [string, unknown]>(a: T, b: T) => a[0].localeCompare(b[0]);
const valueFn = <T extends [string, unknown]>(value: T) => value[1];
export const useValuesChangeWatcher = <T extends Record<string, unknown>>(
valuesToWatch: T,
listener?: (changes: UseValuesChangeWatcherResult<T>) => void
): UseValuesChangeWatcherResult<T> => {
// ensure same order of values
const values = Object.entries(valuesToWatch).sort(compareFn).map(valueFn);
const stored = useRef<T>(valuesToWatch);
const latest = useRef<UseValuesChangeWatcherResult<T>>({});
return useMemo(() => {
const changes: UseValuesChangeWatcherResult<T> = {};
for (const key in valuesToWatch) {
if (valuesToWatch[key] !== stored.current[key]) {
changes[key] = {
oldValue: stored.current[key],
newValue: valuesToWatch[key],
};
}
}
stored.current = valuesToWatch;
latest.current = changes;
// checking if there is at least one change
for (const _ in changes) {
listener?.(changes);
break;
}
return latest.current;
}, values);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment