Last active
August 31, 2023 20:43
-
-
Save MatthewCallis/dc959d1e06f14a0ec931967e0fa83e63 to your computer and use it in GitHub Desktop.
useEffectDebugger See what changed in useEffect
This file contains 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
// https://stackoverflow.com/questions/55187563/determine-which-dependency-array-variable-caused-useeffect-hook-to-fire | |
// https://github.com/simbathesailor/use-what-changed/tree/master | |
// https://dev.to/vsramalwan/ways-to-handle-deep-object-comparison-in-useeffect-hook-1elm | |
import { toJS } from 'mobx' | |
import { useEffect, useRef } from 'react' | |
import type { EffectCallback } from 'react' | |
export interface Update { | |
oldValue: any | |
newValue: any | |
} | |
export interface ObjectDiff { | |
added: {} | ObjectDiff | |
updated: { | |
[propName: string]: Update | ObjectDiff | |
} | |
removed: {} | ObjectDiff | |
unchanged: {} | ObjectDiff | |
} | |
export const isObject = (obj: any) => { | |
return obj !== null && typeof obj === 'object' | |
} | |
/** | |
* @param oldObj The previous Object or Array. | |
* @param newObj The new Object or Array. | |
* @param deep If the comparison must be performed deeper than 1st-level properties. | |
* @return A difference summary between the two objects. | |
*/ | |
export const diff = (oldObj: {} = {}, newObj: {} = {}, deep = true): ObjectDiff => { | |
const added = {} | |
const updated = {} | |
const removed = {} | |
const unchanged = {} | |
for (const oldProp in oldObj) { | |
if (oldObj.hasOwnProperty(oldProp)) { | |
const newPropValue = newObj[oldProp] | |
const oldPropValue = oldObj[oldProp] | |
if (newObj.hasOwnProperty(oldProp)) { | |
if (Object.is(newPropValue, oldPropValue)) { | |
unchanged[oldProp] = oldPropValue | |
} else { | |
updated[oldProp] = | |
deep && isObject(oldPropValue) && isObject(newPropValue) | |
? diff(oldPropValue, newPropValue, deep) | |
: { newValue: newPropValue } | |
} | |
} else { | |
removed[oldProp] = oldPropValue | |
} | |
} | |
} | |
for (const newProp in newObj) { | |
if (newObj.hasOwnProperty(newProp)) { | |
const oldPropValue = oldObj[newProp] | |
const newPropValue = newObj[newProp] | |
if (oldObj.hasOwnProperty(newProp)) { | |
if (!Object.is(oldPropValue, newPropValue)) { | |
if (!deep || !isObject(oldPropValue)) { | |
updated[newProp].oldValue = oldPropValue | |
} | |
} | |
} else { | |
added[newProp] = newPropValue | |
} | |
} | |
} | |
const output = {} as ObjectDiff | |
if (Object.keys(added).length) { | |
output['added'] = added | |
} | |
if (Object.keys(updated).length) { | |
output['updated'] = updated | |
} | |
if (Object.keys(removed).length) { | |
output['removed'] = removed | |
} | |
if (Object.keys(unchanged).length) { | |
output['unchanged'] = unchanged | |
} | |
return output as ObjectDiff | |
// return { added, updated, removed, unchanged } | |
} | |
export const usePrevious = (value: any, initialValue: any) => { | |
const ref = useRef(initialValue) | |
useEffect(() => { | |
ref.current = value | |
}) | |
return ref.current | |
} | |
/** | |
* Hook to debug useEffect to see what has changed in the dependencies. | |
* @param {EffectCallback} effectHook The useEffect hook to debug | |
* @param {any[]} dependencies The useEffect dependencies | |
* @param {string[]} dependencyNames Names for the useEffect dependencies | |
*/ | |
export const useEffectDebugger = (effectHook: EffectCallback, dependencies: any[], dependencyNames: string[] = []) => { | |
const previousDeps = usePrevious(dependencies, []) | |
const changedDeps = dependencies.reduce((accum: any, dependency: any, index: number) => { | |
if (dependency !== previousDeps[index]) { | |
const keyName = dependencyNames[index] || index | |
if (isObject(dependency) || isObject(previousDeps[index])) { | |
console.table(diff(toJS(previousDeps[index]), toJS(dependency))) | |
return { | |
...accum, | |
[keyName]: { | |
Before: diff(toJS(previousDeps[index]), toJS(dependency)), | |
After: diff(toJS(dependency), toJS(previousDeps[index])), | |
// // Diff: diff(toJS(previousDeps[index]), toJS(dependency)), | |
// ...diff(toJS(previousDeps[index]), toJS(dependency)), | |
}, | |
} | |
} | |
return { | |
...accum, | |
[keyName]: { | |
Before: toJS(previousDeps[index]), | |
After: toJS(dependency), | |
}, | |
} | |
} | |
return accum | |
}, {}) | |
if (Object.keys(changedDeps).length) { | |
console.table(changedDeps) | |
} | |
useEffect(effectHook, dependencies) | |
} | |
export default useEffectDebugger |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment