Repository URL to install this package:
|
Version:
1.2.0 ▾
|
"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);
};
}