Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
@skava/modules / ___dist / devtools / why-did-it-update.js
Size: Mime:
"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.createComponentDidUpdate = createComponentDidUpdate;
exports.decorateComponentDidUpdate = decorateComponentDidUpdate;
exports.defaultNotifier = exports.classifyDiff = exports.DIFF_TYPES = void 0;

var _exotic = require("../exotic");

var _isEqual2 = _interopRequireDefault(require("lodash/isEqual"));

var _keys2 = _interopRequireDefault(require("lodash/keys"));

var _union2 = _interopRequireDefault(require("lodash/union"));

var _filter2 = _interopRequireDefault(require("lodash/filter"));

var _every2 = _interopRequireDefault(require("lodash/every"));

var _pick2 = _interopRequireDefault(require("lodash/pick"));

var _identifier = require("../identifier");

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

/**
 * @see https://github.com/maicki/why-did-you-update
 */
const DIFF_TYPES = {
  UNAVOIDABLE: 'unavoidable',
  SAME: 'same',
  EQUAL: 'equal',
  FUNCTIONS: 'functions'
};
exports.DIFF_TYPES = DIFF_TYPES;

const classifyDiff = (prev, next, name) => {
  if (prev === next) {
    return {
      type: DIFF_TYPES.SAME,
      name,
      prev,
      next
    };
  }

  if ((0, _isEqual2.default)(prev, next)) {
    return {
      type: DIFF_TYPES.EQUAL,
      name,
      prev,
      next
    };
  }

  if (!prev || !next) {
    return {
      type: DIFF_TYPES.UNAVOIDABLE,
      name,
      prev,
      next
    };
  }

  const isChanged = key => prev[key] !== next[key] && !(0, _isEqual2.default)(prev[key], next[key]);

  const isSameFunction = key => {
    const prevFn = prev[key];
    const nextFn = next[key];
    return (0, _exotic.isFunction)(prevFn) && (0, _exotic.isFunction)(nextFn) && prevFn.name === nextFn.name;
  };

  const keys = (0, _union2.default)((0, _keys2.default)(prev), (0, _keys2.default)(next));
  const changedKeys = (0, _filter2.default)(keys, isChanged);

  if (changedKeys.length && (0, _every2.default)(changedKeys, isSameFunction)) {
    return {
      type: DIFF_TYPES.FUNCTIONS,
      name,
      prev: (0, _pick2.default)(prev, changedKeys),
      next: (0, _pick2.default)(next, changedKeys)
    };
  }

  return {
    type: DIFF_TYPES.UNAVOIDABLE,
    name,
    prev,
    next
  };
};

exports.classifyDiff = classifyDiff;

const defaultNotifier = (groupByComponent, collapseComponentGroups, displayName, diffs) => {
  if (groupByComponent && collapseComponentGroups) {
    console.groupCollapsed && console.groupCollapsed(displayName);
  } else if (groupByComponent) {
    console.group && console.group(displayName);
  }

  diffs.forEach(notifyDiff);

  if (groupByComponent) {
    console.groupEnd && console.groupEnd();
  }
}; // Disables yellow box in React Native before warn


exports.defaultNotifier = defaultNotifier;

const consoleWarn = args => {
  const oldDisableYellowBox = console.disableYellowBox;
  console.disableYellowBox = true;
  console.warn(args);
  console.disableYellowBox = oldDisableYellowBox;
};

const notifyDiff = ({
  name,
  prev,
  next,
  type
}) => {
  switch (type) {
    case DIFF_TYPES.SAME:
      consoleWarn(`${name}: Value is the same (equal by reference). Avoidable re-render!`);
      console.log(`Value:`, prev);
      break;

    case DIFF_TYPES.EQUAL:
      consoleWarn(`${name}: Value did not change. Avoidable re-render!`);
      console.log(`Before:`, prev);
      console.log(`After:`, next); // TODO: This logic should be moved in deepDiff and return a list of
      //       changed props

      if (prev && next) {
        Object.keys(prev).forEach(key => {
          if (prev[key] !== next[key]) {
            console.log('"' + key + '" property is not equal by reference');
          }
        });
      }

      break;

    case DIFF_TYPES.FUNCTIONS:
      consoleWarn(`${name}: Changes are in functions only. Possibly avoidable re-render?`);
      console.log(`Functions before:`, prev);
      console.log(`Functions after:`, next);
      break;
  }
};

function createComponentDidUpdate(opts = {
  groupByComponent: true,
  notifier: defaultNotifier
}) {
  return function componentDidUpdate(prevProps, prevState) {
    const displayName = (0, _identifier.toComponentName)(this);
    const propsDiff = classifyDiff(prevProps, this.props, `${displayName}.props`);

    if (propsDiff.type === DIFF_TYPES.UNAVOIDABLE) {
      return;
    }

    const stateDiff = classifyDiff(prevState, this.state, `${displayName}.state`);

    if (stateDiff.type === DIFF_TYPES.UNAVOIDABLE) {
      return;
    }

    opts.notifier(opts.groupByComponent, opts.collapseComponentGroups, displayName, [propsDiff, stateDiff]);
  };
}

function decorateComponentDidUpdate(instance) {
  const componentDidUpdateReference = instance.shouldComponentUpdate;
  const whyDidYouUpdate = createComponentDidUpdate();

  instance.componentDidUpdate = (prevProps, prevState) => {
    whyDidYouUpdate.call(instance, prevProps, prevState);
    return componentDidUpdateReference && componentDidUpdateReference.call(instance, prevProps, prevState);
  };
}