rrr-lazy
Version:
Lazy load component with react && react-router.
473 lines (374 loc) • 13.4 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var isDeepEqual = _interopDefault(require('react-fast-compare'));
var createContext = _interopDefault(require('create-react-context'));
var React = _interopDefault(require('react'));
var PropTypes = _interopDefault(require('prop-types'));
var hoistNonReactStatics = _interopDefault(require('hoist-non-react-statics'));
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;
}
function _extends() {
_extends = Object.assign || function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
return _extends.apply(this, arguments);
}
function _objectSpread(target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i] != null ? arguments[i] : {};
var ownKeys = Object.keys(source);
if (typeof Object.getOwnPropertySymbols === 'function') {
ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) {
return Object.getOwnPropertyDescriptor(source, sym).enumerable;
}));
}
ownKeys.forEach(function (key) {
_defineProperty(target, key, source[key]);
});
}
return target;
}
function _inheritsLoose(subClass, superClass) {
subClass.prototype = Object.create(superClass.prototype);
subClass.prototype.constructor = subClass;
subClass.__proto__ = superClass;
}
function _objectWithoutPropertiesLoose(source, excluded) {
if (source == null) return {};
var target = {};
var sourceKeys = Object.keys(source);
var key, i;
for (i = 0; i < sourceKeys.length; i++) {
key = sourceKeys[i];
if (excluded.indexOf(key) >= 0) continue;
target[key] = source[key];
}
return target;
}
function _assertThisInitialized(self) {
if (self === void 0) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return self;
}
var _createContext = createContext(),
LazyProvider = _createContext.Provider,
LazyConsumer = _createContext.Consumer;
var IntersectionListener =
/*#__PURE__*/
function () {
function IntersectionListener(options) {
var _this = this;
this.callbacks = new WeakMap();
this.observer = new IntersectionObserver(function (entries) {
entries.forEach(function (entry) {
var callback = _this.callbacks.get(entry.target);
if (entry.target && callback) {
callback(entry, _this.observer);
} else {
_this.observer.unobserve(entry.target);
}
});
}, options);
}
var _proto = IntersectionListener.prototype;
_proto.listen = function listen(element, callback) {
var _this2 = this;
this.callbacks.set(element, callback);
this.observer.observe(element);
return function () {
_this2.callbacks.delete(element);
_this2.observer.unobserve(element);
};
};
return IntersectionListener;
}();
var observerPool = new WeakMap();
function createIntersectionListener(options) {
var _options$root = options.root,
root = _options$root === void 0 ? typeof window === 'undefined' ? Object : window : _options$root,
_options$rootMargin = options.rootMargin,
rootMargin = _options$rootMargin === void 0 ? '' : _options$rootMargin,
_options$threshold = options.threshold,
threshold = _options$threshold === void 0 ? '' : _options$threshold;
if (!observerPool.get(root)) {
observerPool.set(root, {});
}
var group = observerPool.get(root);
var key = rootMargin + "_" + threshold;
var result = group[key];
if (!result) {
result = new IntersectionListener(options);
group[key] = result;
}
return result;
}
var _Lazy$propTypes, _Lazy$defaultProps;
var Status = {
Unload: 'unload',
Loading: 'loading',
Loaded: 'loaded'
};
var VERSION_PROP = '@@rrr-lazy/Version';
var Lazy =
/*#__PURE__*/
function (_React$Component) {
_inheritsLoose(Lazy, _React$Component);
function Lazy(props) {
var _this;
_this = _React$Component.call(this, props) || this;
_this.startListen = _this.startListen.bind(_assertThisInitialized(_assertThisInitialized(_this)));
_this.stopListen = _this.stopListen.bind(_assertThisInitialized(_assertThisInitialized(_this)));
_this.enterViewport = _this.enterViewport.bind(_assertThisInitialized(_assertThisInitialized(_this)));
var version = props[VERSION_PROP];
_this.state = {
version: version,
// eslint-disable-line react/no-unused-state
status: Status.Unload
};
return _this;
}
Lazy.getDerivedStateFromProps = function getDerivedStateFromProps(props, state) {
var version = props[VERSION_PROP];
if (version !== state.version) {
return {
version: version,
status: Status.Unload
};
}
return {};
};
var _proto = Lazy.prototype;
_proto.componentDidMount = function componentDidMount() {
this.startListen();
};
_proto.shouldComponentUpdate = function shouldComponentUpdate(nextProps, nextState) {
return !isDeepEqual(this.props, nextProps) || !isDeepEqual(this.state, nextState);
};
_proto.componentDidUpdate = function componentDidUpdate(prevProps, prevState) {
var status = this.state.status;
var onUnload = this.props.onUnload;
if (status !== prevState.status && status === Status.Unload) {
if (onUnload) {
onUnload();
}
this.startListen();
}
};
_proto.componentWillUnmount = function componentWillUnmount() {
this.stopListen();
if (this.node) {
this.node = null;
}
};
_proto.startListen = function startListen() {
var _this2 = this;
this.stopListen();
var _this$props = this.props,
root = _this$props.root,
rootMargin = _this$props.rootMargin;
var opts = {};
if (root) {
opts.root = typeof root === 'string' ? document.querySelector(root) : root;
}
if (rootMargin) {
opts.rootMargin = rootMargin;
}
var intersectionListener = createIntersectionListener(opts);
if (this.node && !this.unlisten) {
this.unlisten = intersectionListener.listen(this.node, function (entry) {
if (entry.isIntersecting || entry.intersectionRatio > 0) {
_this2.stopListen();
_this2.enterViewport();
}
});
}
};
_proto.stopListen = function stopListen() {
if (this.unlisten) {
this.unlisten();
this.unlisten = null;
}
};
_proto.enterViewport = function enterViewport() {
var _this3 = this;
var status = this.state.status;
var _this$props2 = this.props,
onLoading = _this$props2.onLoading,
onLoaded = _this$props2.onLoaded,
onError = _this$props2.onError;
if (!this.node || status !== Status.Unload) {
return null;
}
return Promise.resolve().then(function () {
if (!_this3.node) throw new Error('ABORT');
_this3.setState({
status: Status.Loading
});
if (onLoading) {
return onLoading();
}
return null;
}).then(function () {
if (!_this3.node) throw new Error('ABORT');
_this3.setState({
status: Status.Loaded
});
if (onLoaded) {
return onLoaded();
}
return null;
}).catch(function (error) {
if (error.message !== 'ABORT') {
if (onError) {
return onError(error);
}
throw error;
}
return null;
});
};
_proto.render = function render() {
var _this4 = this;
var _this$props3 = this.props,
root = _this$props3.root,
rootMargin = _this$props3.rootMargin,
render = _this$props3.render,
loaderComponent = _this$props3.loaderComponent,
_this$props3$loaderPr = _this$props3.loaderProps,
loaderProps = _this$props3$loaderPr === void 0 ? {} : _this$props3$loaderPr,
onLoaded = _this$props3.onLoaded,
onLoading = _this$props3.onLoading,
onUnload = _this$props3.onUnload,
onError = _this$props3.onError,
restProps = _objectWithoutPropertiesLoose(_this$props3, ["root", "rootMargin", "render", "loaderComponent", "loaderProps", "onLoaded", "onLoading", "onUnload", "onError"]);
var status = this.state.status;
if (status !== Status.Loaded) {
return React.createElement(loaderComponent, _objectSpread({}, loaderProps, {
ref: function ref(node) {
_this4.node = node;
}
}), render(status, restProps));
}
return render(status, restProps);
};
return Lazy;
}(React.Component);
Lazy.propTypes = (_Lazy$propTypes = {}, _Lazy$propTypes[VERSION_PROP] = PropTypes.any, _Lazy$propTypes.render = PropTypes.func.isRequired, _Lazy$propTypes.root = PropTypes.oneOfType([PropTypes.string].concat(typeof HTMLElement === 'undefined' ? [] : PropTypes.instanceOf(HTMLElement))), _Lazy$propTypes.rootMargin = PropTypes.string, _Lazy$propTypes.loaderComponent = PropTypes.string, _Lazy$propTypes.loaderProps = PropTypes.object, _Lazy$propTypes.onError = PropTypes.func, _Lazy$propTypes.onLoaded = PropTypes.func, _Lazy$propTypes.onLoading = PropTypes.func, _Lazy$propTypes.onUnload = PropTypes.func, _Lazy$propTypes);
Lazy.defaultProps = (_Lazy$defaultProps = {}, _Lazy$defaultProps[VERSION_PROP] = null, _Lazy$defaultProps.root = null, _Lazy$defaultProps.rootMargin = null, _Lazy$defaultProps.loaderComponent = 'div', _Lazy$defaultProps.loaderProps = null, _Lazy$defaultProps.onError = null, _Lazy$defaultProps.onLoaded = null, _Lazy$defaultProps.onLoading = null, _Lazy$defaultProps.onUnload = null, _Lazy$defaultProps);
function LazyWrapper(props) {
return React.createElement(LazyConsumer, null, function (version) {
var _objectSpread2;
var passProps = _objectSpread({}, props, (_objectSpread2 = {}, _objectSpread2[VERSION_PROP] = version, _objectSpread2));
return React.createElement(Lazy, passProps);
});
}
function interopRequireDefault(obj) {
// eslint-disable-next-line no-underscore-dangle
return obj && obj.__esModule ? obj : {
default: obj
};
}
function noop() {}
function Empty() {
return null;
}
var LazyDecorated =
/*#__PURE__*/
function (_React$PureComponent) {
_inheritsLoose(LazyDecorated, _React$PureComponent);
function LazyDecorated(props) {
var _this;
_this = _React$PureComponent.call(this, props) || this;
_this.handleLoading = _this.handleLoading.bind(_assertThisInitialized(_assertThisInitialized(_this)));
_this.renderComponent = _this.renderComponent.bind(_assertThisInitialized(_assertThisInitialized(_this)));
_this.state = {
Component: null
};
return _this;
}
var _proto = LazyDecorated.prototype;
_proto.handleLoading = function handleLoading() {
var _this2 = this;
var _this$props = this.props,
getComponent = _this$props.getComponent,
lazyProps = _this$props.lazyProps;
var _lazyProps$onLoading = lazyProps.onLoading,
onLoading = _lazyProps$onLoading === void 0 ? noop : _lazyProps$onLoading;
return Promise.resolve().then(function () {
return getComponent();
}).then(function (c) {
var Component = interopRequireDefault(c).default || Empty;
_this2.setState({
Component: Component
});
return onLoading();
});
};
_proto.renderComponent = function renderComponent(status, props) {
var Component = this.state.Component;
var lazyProps = this.props.lazyProps;
var render = lazyProps.render;
if (typeof render === 'function') {
return render(status, props, Component);
}
if (!Component || status !== 'loaded') return null;
return React.createElement(Component, props);
};
_proto.render = function render() {
var _this$props2 = this.props,
lazyProps = _this$props2.lazyProps,
ownProps = _this$props2.ownProps;
return React.createElement(LazyWrapper, _extends({}, ownProps, lazyProps, {
render: this.renderComponent,
onLoading: this.handleLoading
}));
};
return LazyDecorated;
}(React.PureComponent);
LazyDecorated.propTypes = {
getComponent: PropTypes.func.isRequired,
lazyProps: PropTypes.object.isRequired,
ownProps: PropTypes.object.isRequired
};
var lazy = function lazy(opts) {
return function (WrappedComponent) {
var getComponent = opts.getComponent,
lazyProps = _objectWithoutPropertiesLoose(opts, ["getComponent"]);
var Component = function Component(ownProps) {
return React.createElement(LazyDecorated, {
getComponent: getComponent === 'function' ? getComponent : function () {
return WrappedComponent;
},
lazyProps: lazyProps,
ownProps: ownProps
});
};
Component.WrappedComponent = WrappedComponent;
hoistNonReactStatics(Component, WrappedComponent);
return Component;
};
};
exports.Lazy = LazyWrapper;
exports.lazy = lazy;
exports.LazyProvider = LazyProvider;