@moxy/react-page-swapper
Version:
An orchestrator that eases out the implementation of page transitions
109 lines (90 loc) • 3.22 kB
JavaScript
import _omit from "lodash/omit";
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
import { Component } from 'react';
import PropTypes from 'prop-types';
import shallowequal from 'shallowequal';
import memoizeOne from 'memoize-one';
import once from 'once';
export default class SwapTransition extends Component {
constructor(...args) {
super(...args);
_defineProperty(this, "state", {
transitioning: false
});
_defineProperty(this, "wrapOnEntered", memoizeOne(onEntered => once(async () => {
const {
in: inProp,
transitioning
} = this.state;
if (!inProp || !transitioning) {
return;
}
await Promise.resolve();
this.setState({
transitioning: false
}, () => {
onEntered === null || onEntered === void 0 ? void 0 : onEntered();
});
})));
_defineProperty(this, "wrapOnExited", memoizeOne(onExited => once(async () => {
const {
in: inProp,
transitioning
} = this.state;
if (inProp || !transitioning) {
return;
}
await Promise.resolve(); // `transitioning` is not changed to false as the view will be unmounted afterwards
// This effectively avoids one useless re-render
onExited === null || onExited === void 0 ? void 0 : onExited();
})));
}
static getDerivedStateFromProps(props, state) {
let transitioning; // Transitioning is set to true if the `in` prop changed
// There's an exception which is when mounting, which we take into consideration the `hasPrevNode` prop
if (props.in !== state.in) {
transitioning = state.in == null ? !!props.prevNodeKey : true;
} else {
transitioning = state.transitioning;
}
return { // TransitionGroup adds the properties below, so we filter them out
..._omit(props, ['appear', 'enter', 'exit', 'onExited']),
// TransitionGroup changes `onExited` in every render unnecessarily,
// so we keep it constant to avoid re-renders
onExited: state.onExited || props.onExited,
transitioning
};
}
shouldComponentUpdate(prevProps, prevState) {
// Only update when state changes, which was derived in `getDerivedStateFromProps`
return !shallowequal(this.state, prevState);
}
render() {
const {
children,
onEntered,
onExited,
...rest
} = this.state;
return children({ ...rest,
onEntered: this.wrapOnEntered(onEntered),
onExited: this.wrapOnExited(onExited)
});
} // eslint-disable-next-line react/sort-comp
}
_defineProperty(SwapTransition, "propTypes", {
node: PropTypes.element.isRequired,
nodeKey: PropTypes.string.isRequired,
prevNodeKey: PropTypes.string,
mode: PropTypes.oneOf(['simultaneous', 'out-in']).isRequired,
animation: PropTypes.string,
in: PropTypes.bool,
style: PropTypes.object,
onEntered: PropTypes.func,
onExited: PropTypes.func,
children: PropTypes.func.isRequired
});
_defineProperty(SwapTransition, "defaultProps", {
in: false,
style: {}
});