UNPKG

react-keep-alive

Version:

Package will allow components to maintain their status, to avoid repeated re-rendering.

260 lines (259 loc) 14.7 kB
"use strict"; var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) t[p[i]] = s[p[i]]; return t; }; var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; result["default"] = mod; return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); var React = __importStar(require("react")); var hoist_non_react_statics_1 = __importDefault(require("hoist-non-react-statics")); var IdentificationContext_1 = __importDefault(require("../contexts/IdentificationContext")); var Consumer_1 = __importDefault(require("../components/Consumer")); var Provider_1 = require("../components/Provider"); var md5_1 = __importDefault(require("./md5")); var debug_1 = require("./debug"); var getKeyByFiberNode_1 = __importDefault(require("./getKeyByFiberNode")); var withIdentificationContextConsumer_1 = __importDefault(require("./withIdentificationContextConsumer")); var withKeepAliveContextConsumer_1 = __importDefault(require("./withKeepAliveContextConsumer")); var shallowEqual_1 = __importDefault(require("./shallowEqual")); var getKeepAlive_1 = __importDefault(require("./getKeepAlive")); var COMMAND; (function (COMMAND) { COMMAND["UNACTIVATE"] = "unactivate"; COMMAND["UNMOUNT"] = "unmount"; COMMAND["ACTIVATE"] = "activate"; COMMAND["CURRENT_UNMOUNT"] = "current_unmount"; COMMAND["CURRENT_UNACTIVATE"] = "current_unactivate"; })(COMMAND = exports.COMMAND || (exports.COMMAND = {})); /** * Decorating the <KeepAlive> component, the main function is to listen to events emitted by the upper <KeepAlive> component, triggering events of the current <KeepAlive> component. * * @export * @template P * @param {React.ComponentType<any>} Component * @returns {React.ComponentType<P>} */ function keepAliveDecorator(Component) { var TriggerLifecycleContainer = /** @class */ (function (_super) { __extends(TriggerLifecycleContainer, _super); function TriggerLifecycleContainer(props) { var args = []; for (var _i = 1; _i < arguments.length; _i++) { args[_i - 1] = arguments[_i]; } var _this = _super.apply(this, [props].concat(args)) || this; _this.activated = false; _this.ifStillActivate = false; // Let the lifecycle of the cached component be called normally. _this.needActivate = true; _this.lifecycle = Provider_1.LIFECYCLE.MOUNTED; _this.activate = function () { _this.activated = true; }; _this.reactivate = function () { _this.ifStillActivate = false; _this.forceUpdate(); }; _this.isNeedActivate = function () { return _this.needActivate; }; _this.notNeedActivate = function () { _this.needActivate = false; }; _this.getLifecycle = function () { return _this.lifecycle; }; _this.setLifecycle = function (lifecycle) { _this.lifecycle = lifecycle; }; var cache = props._keepAliveContextProps.cache; if (!cache) { debug_1.warn('[React Keep Alive] You should not use <KeepAlive> outside a <Provider>.'); } return _this; } TriggerLifecycleContainer.prototype.componentDidMount = function () { if (!this.ifStillActivate) { this.activate(); } var _a = this.props, keepAlive = _a.keepAlive, eventEmitter = _a._keepAliveContextProps.eventEmitter; if (keepAlive) { this.needActivate = true; eventEmitter.emit([this.identification, COMMAND.ACTIVATE]); } }; TriggerLifecycleContainer.prototype.componentDidCatch = function () { if (!this.activated) { this.activate(); } }; TriggerLifecycleContainer.prototype.componentWillUnmount = function () { var _a = this.props, getCombinedKeepAlive = _a.getCombinedKeepAlive, _b = _a._keepAliveContextProps, eventEmitter = _b.eventEmitter, isExisted = _b.isExisted; var keepAlive = getCombinedKeepAlive(); if (!keepAlive || !isExisted()) { eventEmitter.emit([this.identification, COMMAND.CURRENT_UNMOUNT]); eventEmitter.emit([this.identification, COMMAND.UNMOUNT]); } // When the Provider components are unmounted, the cache is not needed, // so you don't have to execute the componentWillUnactivate lifecycle. if (keepAlive && isExisted()) { eventEmitter.emit([this.identification, COMMAND.CURRENT_UNACTIVATE]); eventEmitter.emit([this.identification, COMMAND.UNACTIVATE]); } }; TriggerLifecycleContainer.prototype.render = function () { var _a = this.props, propKey = _a.propKey, keepAlive = _a.keepAlive, extra = _a.extra, getCombinedKeepAlive = _a.getCombinedKeepAlive, _b = _a._keepAliveContextProps, isExisted = _b.isExisted, storeElement = _b.storeElement, cache = _b.cache, eventEmitter = _b.eventEmitter, setCache = _b.setCache, unactivate = _b.unactivate, providerIdentification = _b.providerIdentification, wrapperProps = __rest(_a, ["propKey", "keepAlive", "extra", "getCombinedKeepAlive", "_keepAliveContextProps"]); if (!this.identification) { // We need to generate a corresponding unique identifier based on the information of the component. this.identification = md5_1.default("" + providerIdentification + propKey); // The last activated component must be unactivated before it can be activated again. var currentCache = cache[this.identification]; if (currentCache) { this.ifStillActivate = currentCache.activated; currentCache.ifStillActivate = this.ifStillActivate; currentCache.reactivate = this.reactivate; } } var _c = this, isNeedActivate = _c.isNeedActivate, notNeedActivate = _c.notNeedActivate, activated = _c.activated, getLifecycle = _c.getLifecycle, setLifecycle = _c.setLifecycle, identification = _c.identification, ifStillActivate = _c.ifStillActivate; return !ifStillActivate ? (React.createElement(Consumer_1.default, { identification: identification, keepAlive: keepAlive, cache: cache, setCache: setCache, unactivate: unactivate }, React.createElement(IdentificationContext_1.default.Provider, { value: { identification: identification, eventEmitter: eventEmitter, keepAlive: keepAlive, activated: activated, getLifecycle: getLifecycle, isExisted: isExisted, extra: extra, } }, React.createElement(Component, __assign({}, wrapperProps, { _container: { isNeedActivate: isNeedActivate, notNeedActivate: notNeedActivate, setLifecycle: setLifecycle, eventEmitter: eventEmitter, identification: identification, storeElement: storeElement, keepAlive: keepAlive, cache: cache, } }))))) : null; }; return TriggerLifecycleContainer; }(React.PureComponent)); var ListenUpperKeepAliveContainer = /** @class */ (function (_super) { __extends(ListenUpperKeepAliveContainer, _super); function ListenUpperKeepAliveContainer() { var _this = _super !== null && _super.apply(this, arguments) || this; _this.state = { activated: true, }; _this.getCombinedKeepAlive = function () { return _this.combinedKeepAlive; }; return _this; } ListenUpperKeepAliveContainer.prototype.shouldComponentUpdate = function (nextProps, nextState) { if (this.state.activated !== nextState.activated) { return true; } var _a = this.props, _keepAliveContextProps = _a._keepAliveContextProps, _identificationContextProps = _a._identificationContextProps, rest = __rest(_a, ["_keepAliveContextProps", "_identificationContextProps"]); var nextKeepAliveContextProps = nextProps._keepAliveContextProps, nextIdentificationContextProps = nextProps._identificationContextProps, nextRest = __rest(nextProps, ["_keepAliveContextProps", "_identificationContextProps"]); if (!shallowEqual_1.default(rest, nextRest)) { return true; } if (!shallowEqual_1.default(_keepAliveContextProps, nextKeepAliveContextProps) || !shallowEqual_1.default(_identificationContextProps, nextIdentificationContextProps)) { return true; } return false; }; ListenUpperKeepAliveContainer.prototype.componentDidMount = function () { this.listenUpperKeepAlive(); }; ListenUpperKeepAliveContainer.prototype.componentWillUnmount = function () { this.unlistenUpperKeepAlive(); }; ListenUpperKeepAliveContainer.prototype.listenUpperKeepAlive = function () { var _this = this; var _a = this.props._identificationContextProps, identification = _a.identification, eventEmitter = _a.eventEmitter; if (!identification) { return; } eventEmitter.on([identification, COMMAND.ACTIVATE], this.activate = function () { return _this.setState({ activated: true }); }, true); eventEmitter.on([identification, COMMAND.UNACTIVATE], this.unactivate = function () { return _this.setState({ activated: false }); }, true); eventEmitter.on([identification, COMMAND.UNMOUNT], this.unmount = function () { return _this.setState({ activated: false }); }, true); }; ListenUpperKeepAliveContainer.prototype.unlistenUpperKeepAlive = function () { var _a = this.props._identificationContextProps, identification = _a.identification, eventEmitter = _a.eventEmitter; if (!identification) { return; } eventEmitter.off([identification, COMMAND.ACTIVATE], this.activate); eventEmitter.off([identification, COMMAND.UNACTIVATE], this.unactivate); eventEmitter.off([identification, COMMAND.UNMOUNT], this.unmount); }; ListenUpperKeepAliveContainer.prototype.render = function () { var _a = this.props, _b = _a._identificationContextProps, identification = _b.identification, upperKeepAlive = _b.keepAlive, getLifecycle = _b.getLifecycle, disabled = _a.disabled, name = _a.name, wrapperProps = __rest(_a, ["_identificationContextProps", "disabled", "name"]); var activated = this.state.activated; var _c = wrapperProps._keepAliveContextProps, include = _c.include, exclude = _c.exclude; // When the parent KeepAlive component is mounted or unmounted, // use the keepAlive prop of the parent KeepAlive component. var propKey = name || getKeyByFiberNode_1.default(this._reactInternalFiber); if (!propKey) { debug_1.warn('[React Keep Alive] <KeepAlive> components must have key or name.'); return null; } var newKeepAlive = getKeepAlive_1.default(propKey, include, exclude, disabled); this.combinedKeepAlive = getLifecycle === undefined || getLifecycle() === Provider_1.LIFECYCLE.UPDATING ? newKeepAlive : identification ? upperKeepAlive && newKeepAlive : newKeepAlive; return activated ? (React.createElement(TriggerLifecycleContainer, __assign({}, wrapperProps, { key: propKey, propKey: propKey, keepAlive: this.combinedKeepAlive, getCombinedKeepAlive: this.getCombinedKeepAlive }))) : null; }; return ListenUpperKeepAliveContainer; }(React.Component)); var KeepAlive = withKeepAliveContextConsumer_1.default(withIdentificationContextConsumer_1.default(ListenUpperKeepAliveContainer)); return hoist_non_react_statics_1.default(KeepAlive, Component); } exports.default = keepAliveDecorator;