Skip to content

Instantly share code, notes, and snippets.

@sashadev-sky
Last active December 1, 2022 03:17
Show Gist options
  • Save sashadev-sky/50c44d55218e9ffb65960000774cc174 to your computer and use it in GitHub Desktop.
Save sashadev-sky/50c44d55218e9ffb65960000774cc174 to your computer and use it in GitHub Desktop.
This hook makes it easy to see which prop changes are causing a component to re-render.
/**
* Prints out the keys that changed and their old and new values. Useful for deeply
* nested objects.
* Bare minimum Typescript annotations to pass compiling
**/
import _ from 'lodash';
import { useEffect, useRef } from 'react';
const isObject = (v: any) => v && typeof v === 'object';
// Hook
function useWhyDidYouUpdateKeys(name: any, props: { [x: string]: any; }) {
/**
* Get a mutable ref object where we can store props ...
* ... for comparison next time this hook runs.
**/
const previousProps: any = useRef();
useEffect(() => {
if (previousProps.current) {
// Get all keys from previous and current props
const allKeys = Object.keys({ ...previousProps.current, ...props });
// Use this object to keep track of changed props
const changesObj: any = {};
// Iterate through keys
allKeys.forEach((key) => {
const prev = previousProps.current[key];
const up = props[key];
// If previous is different from current
if (prev !== up) {
// If both are objects, then create an array of objects out of the different properties
// the top-level key is the name of the field thats different, and the values are
// the old and new values of the key represented by 'from' and 'to', respectively.
if (isObject(prev) && isObject(up)) {
const diff: any = _.reduce(prev, (res: any[], v, k): any => (
_.isEqual(v, up[k]) ? res : res.concat({ [k]: { from: v, to: up[k] } })
), []);
// add each property to the changesObj
diff.forEach((el: any) => {
const k = Object.keys(el)[0];
changesObj[k] = el[k];
});
} else {
// If previous and updated props are not objects,
// add them directly to the changes objects in the same format
changesObj[key] = {
from: previousProps.current[key],
to: props[key],
};
}
}
});
// If changesObj not empty then output to console
if (Object.keys(changesObj).length) {
console.log('[why-did-you-update]', name, changesObj);
}
}
// Finally update previousProps with current props for next hook call
previousProps.current = props;
});
}
interface Props {
captions: string[];
initialValues: FormValues;
onSubmit: (values: ListForSaleFormValues) => void
}
const MyComponent = ({ captions = [], initialValues, onSubmit }: Props) => {
/* include all props here, also values from hooks that might need to be optimized */
useWhyDidYouUpdateKeys('MyComponent', { captions = [], initialValues, onSubmit });
/* rest of the component.... */
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment