"Why does it rerender?" - a little utility to help

András Tóth - Jan 5 - - Dev Community

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];
    }
  });
}

Enter fullscreen mode Exit fullscreen mode

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!
Enter fullscreen mode Exit fullscreen mode

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!

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .