Hi everyone!
I spent some time tracking down why is a useMemo
computation called every time I pressed an unrelated button and I was going crazy.
After I have found the culprit I had an idea to create a hook
that could do just spit out which of my dependencies changed.
import { useRef } from 'react';
type DependenciesObject = {
[dependencyName: string]: any;
};
export function useDependencySpy(dependenciesObject: DependenciesObject) {
const listOfRefs = Object.entries(dependenciesObject).map(([key, value]) => ({ key, originalObject: useRef(value) }));
listOfRefs.forEach((ref) => {
if (!Object.is(ref.originalObject.current, dependenciesObject[ref.key])) {
console.info(`[${ref.key}] variable reference has changed!`);
ref.originalObject.current = dependenciesObject[ref.key];
}
});
}
Let me walk through the code!
Passing in an object
I will need both the object and its original variable name, so I can print it in the console.
Therefore I decided to use an object for that. To use it, it's quite easy:
// our dependencies
// overmind is the best state management tool
// way easier than redux or zustand! 😉
const { user: { id, name } } = useOvermindState();
useDependencySpy({ id, name });
// will output if `id` or `name` has changed or both!
Saving a list of references
Now that I will be able to print the variable names, I am iterating over this parameter object to create a ref
for each of them.
I will get an array like this:
[ { variableName: 'id', originalObject: { dbId: 13, authorId: 123 } }, { variableName: 'name', originalObject: 'Hermann' } }]
The check if they have changed
Every time the parameter changes a check against the saved values will run. To find which ones exactlyI iterate over the arrayOfReferences
and check if the references are still the same or not using Object.is
(as per React documentation on how it knows it has to run an effect again).
If not, I print out the variable name.
Making sure we catch the next change
But we are not done yet. If we don't do anything, this function will forever track the first value it held.
Therefore after printing out the name of the changed variable, I have update the reference through setting ref.originalObject.current
.
Thanks very much for reading it and hope it was easy to follow for #beginners! Have a great day!