Home Reference Source Repository

src/debug.js

import debug from 'debug';
import { is } from 'immutable';
import union from 'lodash.union';
import keys from 'lodash.keys';
import { getComponentName } from './util';

/**
 * @typedef {Object} Change
 * @property {string} component the component name
 * @property {string} type string containing either 'props' or 'state'
 * @property {any} from the original value of the change
 * @property {any} to the new value of the change
 */

 /**
  * The default log funcion to be used
  * @type {function}
  * @since 1.0.0
  */
const logFunc = debug('ReactUpdateHelper');

/**
 * Log and return the changes in a component as they occur to help with debugging
 * @protected
 * @param {object} context - the component context
 * @param {object} context.props - the component props object
 * @param {object} context.state - the component state object
 * @param {object} nProps - the next props in the update process
 * @param {object} nState - the next state in the update process
 * @param {function} log - the log function to use when logging changes
 * @return {Array<Change>} - the changes that took place
 * @since 1.0.0
 */
export function reportChanges(context, nProps, nState, log = logFunc) {
  const props = context.props || {};
  const state = context.state || {};
  const newProps = nProps || {};
  const newState = nState || {};
  const availableProps = union(keys(props), keys(newProps));
  const stateKeys = union(keys(state), keys(newState));
  const name = getComponentName(context);
  const changes = [];
  availableProps.forEach((key) => {
    const oldValue = props[key];
    const newValue = newProps[key];
    if (!is(oldValue, newValue)) {
      changes.push({
        component: name,
        type: 'props',
        from: props[key],
        to: newProps[key],
      });
      log('%s: changed prop %s from %o to %o', name, key, oldValue, newValue);
    }
  });
  stateKeys.forEach((key) => {
    const oldValue = state[key];
    const newValue = newState[key];
    if (!is(oldValue, newValue)) {
      changes.push({
        component: name,
        type: 'state',
        from: state[key],
        to: newState[key],
      });
      log('%s: changed state key %s from %o to %o', name, key, oldValue, newValue);
    }
  });
  return changes;
}