gloriaJun / til

Lessoned Learned
3 stars 0 forks source link

whyComponentDidUpdate #70

Open gloriaJun opened 4 years ago

gloriaJun commented 4 years ago

To monitoring why components did update.

hooks

import { useEffect, useRef } from 'react';

export default function useWhyDidYouUpdate(name, props) {
  // Get a mutable ref object where we can store props ...
  // ... for comparison next time this hook runs.
  const previousProps = 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 = {};
      // Iterate through keys
      allKeys.forEach(key => {
        // If previous is different from current
        if (previousProps.current[key] !== props[key]) {
          // Add to changesObj
          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;
  });
}

Utility function

/**
 * To check why did component update
 * @param prevProps
 * @param prevState
 * @param snapshot
 * ex) CommonUtils.whyComponentDidUpdate.call(this, { prevProps, prevState, snapshot });
 */
function whyComponentDidUpdate({ prevProps, prevState, snapshot }) {
  if (process.env.NODE_ENV === 'production') return false;

  const { props, state, constructor } = this;

  if (!props && !state) {
    console.error('you have call this function using "Function.prototype.call()"');
    console.error('==> ex) CommonUtils.whyComponentDidUpdate.call(this, { prevProps, prevState, snapshot });');
    return false;
  }

  const checkModifiedObj = (prev, current, target) => {
    if (prev !== current) {
      Object.keys(current).map(key => {
        ((!prev[key] && current[key]) || prev[key] !== current[key]) &&
          console.log(
            `[${constructor.name}] updated ${target} /`,
            key,
            ': prev =>',
            prev[key],
            ', current =>',
            current[key],
            'isSameObject => ',
            ObjectUtils.compare(prev[key], current[key])
          );
      });
    }
  };
  prevProps && checkModifiedObj(prevProps, props, 'props');
  prevState && checkModifiedObj(prevState, state, 'state');
  snapshot && console.log(`[SelectRepresentative] updated snapshot /`, snapshot);
}