Skip to content

Instantly share code, notes, and snippets.

@rafaelgandi
Created May 25, 2022 10:05
Show Gist options
  • Save rafaelgandi/d0d954e9ff1d1e8517aa888b7fe71470 to your computer and use it in GitHub Desktop.
Save rafaelgandi/d0d954e9ff1d1e8517aa888b7fe71470 to your computer and use it in GitHub Desktop.
useSpecialEffect Implementation
import React from "react";
export default function useSpecialEffect(
callback: (prevRef: any) => any,
updatables: any = {} // Passing false here means the effect will only run once. Like passing [] to useEffect()
): void {
const prevRef = React.useRef<any>({});
const renderCountRef = React.useRef<number>(0);
prevRef.current.update = (propertyString: string, value: any) => {
if (!(propertyString in prevRef.current)) {
prevRef.current[propertyString] = null;
}
prevRef.current[propertyString] = value;
};
prevRef.current.hasChanged = (...args: any) => {
const hasAnythingChanged: boolean[] = args.map((check: any) => {
if (check instanceof Array) {
return !Object.is(check[0], check[1]);
}
else {
for (let p in check) {
if (!(p in prevRef.current)) {
if (renderCountRef.current > 1) {
throw new Error(`useSpecialEffect() -> Looks like you are missing updatable "${p}". Please remove it from .hasChanged() or add it to the updatables object. For example: useSpecialEffect(..., {${p}, ...})`);
}
return true;
}
return !Object.is(prevRef.current[p], check[p]);
}
return false;
}
});
let i = 0;
while (i < hasAnythingChanged.length) {
if (hasAnythingChanged[i]) {
return true;
}
i++;
}
return false;
};
React.useEffect(() => {
// console.log(callback.toString());
const cleanUp = callback(prevRef.current);
for (let p in updatables) {
prevRef.current.update(p, updatables[p]);
}
renderCountRef.current++;
return cleanUp;
// eslint-disable-next-line react-hooks/exhaustive-deps
}, ((updatables === false) ? [] : undefined));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment