@modus/react-idle
Version:
Render components when browser is idle
175 lines (174 loc) • 8.91 kB
JavaScript
!function(global, factory) {
"object" == typeof exports && "undefined" != typeof module ? module.exports = factory(require("react")) : "function" == typeof define && define.amd ? define([ "react" ], factory) : global.ReactIdle = factory(global.React);
}("undefined" != typeof self ? self : this, function(React) {
"use strict";
const now = () => +new Date(), supportsRequestIdleCallback_ = "function" == typeof requestIdleCallback;
class IdleDeadline {
constructor(initTime) {
this.initTime_ = initTime;
}
get didTimeout() {
return !1;
}
timeRemaining() {
return Math.max(0, 50 - (now() - this.initTime_));
}
}
const rIC = supportsRequestIdleCallback_ ? requestIdleCallback : callback => {
const deadline = new IdleDeadline(now());
return setTimeout(() => callback(deadline), 0);
}, cIC = supportsRequestIdleCallback_ ? cancelIdleCallback : handle => {
clearTimeout(handle);
}, queueMicrotask = "function" == typeof Promise && Promise.toString().indexOf("[native code]") > -1 ? (() => microtask => {
Promise.resolve().then(microtask);
})() : (() => {
let i = 0, microtaskQueue = [];
const observer = new MutationObserver(() => {
microtaskQueue.forEach(microtask => microtask()), microtaskQueue = [];
}), node = document.createTextNode("");
return observer.observe(node, {
characterData: !0
}), microtask => {
microtaskQueue.push(microtask), node.data = String(++i % 2);
};
})(), DEFAULT_MIN_TASK_TIME = 0, isSafari_ = !("object" != typeof safari || !safari.pushNotification);
const shouldYield = (deadline, minTaskTime) => !!(deadline && deadline.timeRemaining() <= minTaskTime);
var classCallCheck = function(instance, Constructor) {
if (!(instance instanceof Constructor)) throw new TypeError("Cannot call a class as a function");
}, createClass = function() {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || !1, descriptor.configurable = !0,
"value" in descriptor && (descriptor.writable = !0), Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function(Constructor, protoProps, staticProps) {
return protoProps && defineProperties(Constructor.prototype, protoProps), staticProps && defineProperties(Constructor, staticProps),
Constructor;
};
}(), possibleConstructorReturn = function(self, call) {
if (!self) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
return !call || "object" != typeof call && "function" != typeof call ? self : call;
}, queue = new class {
constructor({ensureTasksRun: ensureTasksRun = !1, defaultMinTaskTime: defaultMinTaskTime = DEFAULT_MIN_TASK_TIME} = {}) {
this.idleCallbackHandle_ = null, this.taskQueue_ = [], this.isProcessing_ = !1,
this.state_ = null, this.defaultMinTaskTime_ = defaultMinTaskTime, this.ensureTasksRun_ = ensureTasksRun,
this.runTasksImmediately = this.runTasksImmediately.bind(this), this.runTasks_ = this.runTasks_.bind(this),
this.onVisibilityChange_ = this.onVisibilityChange_.bind(this), this.ensureTasksRun_ && (addEventListener("visibilitychange", this.onVisibilityChange_, !0),
isSafari_ && addEventListener("beforeunload", this.runTasksImmediately, !0));
}
pushTask(...args) {
this.addTask_(Array.prototype.push, ...args);
}
unshiftTask(...args) {
this.addTask_(Array.prototype.unshift, ...args);
}
runTasksImmediately() {
this.runTasks_();
}
hasPendingTasks() {
return this.taskQueue_.length > 0;
}
clearPendingTasks() {
this.taskQueue_ = [], this.cancelScheduledRun_();
}
getState() {
return this.state_;
}
destroy() {
this.taskQueue_ = [], this.cancelScheduledRun_(), this.ensureTasksRun_ && (removeEventListener("visibilitychange", this.onVisibilityChange_, !0),
isSafari_ && removeEventListener("beforeunload", this.runTasksImmediately, !0));
}
addTask_(arrayMethod, task, {minTaskTime: minTaskTime = this.defaultMinTaskTime_} = {}) {
const state = {
time: now(),
visibilityState: document.visibilityState
};
arrayMethod.call(this.taskQueue_, {
state: state,
task: task,
minTaskTime: minTaskTime
}), this.scheduleTasksToRun_();
}
scheduleTasksToRun_() {
this.ensureTasksRun_ && "hidden" === document.visibilityState ? queueMicrotask(this.runTasks_) : this.idleCallbackHandle_ || (this.idleCallbackHandle_ = rIC(this.runTasks_));
}
runTasks_(deadline) {
if (this.cancelScheduledRun_(), !this.isProcessing_) {
for (this.isProcessing_ = !0; this.hasPendingTasks() && !shouldYield(deadline, this.taskQueue_[0].minTaskTime); ) {
const {task: task, state: state} = this.taskQueue_.shift();
this.state_ = state, task(state), this.state_ = null;
}
this.isProcessing_ = !1, this.hasPendingTasks() && this.scheduleTasksToRun_();
}
}
cancelScheduledRun_() {
cIC(this.idleCallbackHandle_), this.idleCallbackHandle_ = null;
}
onVisibilityChange_() {
"hidden" === document.visibilityState && this.runTasksImmediately();
}
}(), isBrowser = !("undefined" == typeof window || !window.document || !window.document.createElement), OnIdle = function(_React$Component) {
function OnIdle() {
var _ref, _temp, _this;
classCallCheck(this, OnIdle);
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) args[_key] = arguments[_key];
return _temp = _this = possibleConstructorReturn(this, (_ref = OnIdle.__proto__ || Object.getPrototypeOf(OnIdle)).call.apply(_ref, [ this ].concat(args))),
_this.state = {
ready: !1
}, _this.job = null, _this.clearJob = function() {
queue.unshiftTask(_this.queueRendering);
}, _this.requestIdle = function() {
_this.clearJob(), !0 !== _this.props.skipSSR && (_this.job = queue.pushTask(_this.queueRendering));
}, _this.queueRendering = function() {
requestAnimationFrame(_this.readyToRender);
}, _this.readyToRender = function() {
_this.setState({
ready: !0
});
}, possibleConstructorReturn(_this, _temp);
}
return function(subClass, superClass) {
if ("function" != typeof superClass && null !== superClass) throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
enumerable: !1,
writable: !0,
configurable: !0
}
}), superClass && (Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass);
}(OnIdle, React.Component), createClass(OnIdle, [ {
key: "componentDidMount",
value: function() {
this.requestIdle();
}
}, {
key: "componentWillReceiveProps",
value: function(nextProps) {
this.props.syncUpdate || this.props.children === nextProps.children || (this.setState({
ready: !1
}), this.requestIdle());
}
}, {
key: "componentDidUpdate",
value: function(prevProps, prevState) {
!prevState.ready && this.state.ready && "function" == typeof this.props.onRender && this.props.onRender();
}
}, {
key: "componentWillUnmount",
value: function() {
this.clearJob();
}
}, {
key: "render",
value: function() {
return !isBrowser && this.props.skipSSR ? null : this.state.ready ? this.props.children : this.props.placeholder || null;
}
} ]), OnIdle;
}();
return OnIdle.defaultProps = {
placeholder: null
}, OnIdle;
});