UNPKG

react-next-keep-alive

Version:
301 lines (292 loc) 11 kB
var React = require('react'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var React__default = /*#__PURE__*/_interopDefaultLegacy(React); function _extends() { _extends = Object.assign ? Object.assign.bind() : 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); } var defaultEnabled = true; var KeepAliveProvider = function KeepAliveProvider(props) { var _componentData$type; var children = props.children, router = props.router; var pageProps = children == null ? void 0 : children.props; var componentData = React.cloneElement(children); var CurrentComponent = componentData == null ? void 0 : componentData.type; var keepAliveCache = React.useRef({}); var _useState = React.useState(), forceUpdate = _useState[1]; var _ref = (componentData == null || (_componentData$type = componentData.type) == null ? void 0 : _componentData$type.keepAlive) || {}, keepAliveName = _ref.name, keepScrollEnabled = _ref.keepScrollEnabled, applyNewProps = _ref.applyNewProps; // KeepAlive name var name = typeof keepAliveName === 'function' ? keepAliveName({ props: pageProps, router: router }) : keepAliveName; var isEnabled = function isEnabled() { var _keepAliveCache$curre; return keepAliveCache == null || (_keepAliveCache$curre = keepAliveCache.current) == null || (_keepAliveCache$curre = _keepAliveCache$curre[name]) == null ? void 0 : _keepAliveCache$curre.enabled; }; var isKeptAlive = !!name; var keepScroll = !!keepScrollEnabled; // Add Component to retainedComponents if we haven't got it already if (isKeptAlive && !keepAliveCache.current[name]) { var Component = componentData == null ? void 0 : componentData.type; var MemoComponent = React.memo(Component); keepAliveCache.current[name] = { Component: MemoComponent, pageProps: pageProps, scrollPos: 0, name: name, enabled: defaultEnabled }; } // Save the scroll position of current page before leaving var handleRouteChangeStart = function handleRouteChangeStart() { var _keepAliveCache$curre2; if (isKeptAlive && keepAliveCache != null && (_keepAliveCache$curre2 = keepAliveCache.current) != null && _keepAliveCache$curre2[name]) { keepAliveCache.current[name].scrollPos = window.scrollY; } }; // Restore the scroll position of cached page var handleRouteChangeComplete = function handleRouteChangeComplete() { if (isKeptAlive && isEnabled() && keepScroll) { var _keepAliveCache$curre3; window.scrollTo(0, ((_keepAliveCache$curre3 = keepAliveCache.current[name]) == null ? void 0 : _keepAliveCache$curre3.scrollPos) || 0); // Just in case try again in next event loop setTimeout(function () { var _keepAliveCache$curre4; window.scrollTo(0, ((_keepAliveCache$curre4 = keepAliveCache.current[name]) == null ? void 0 : _keepAliveCache$curre4.scrollPos) || 0); }, 0); } }; // Enable/disable loading from cache var handleLoadFromCache = function handleLoadFromCache(event) { var _ref2 = (event == null ? void 0 : event.detail) || {}, controlsName = _ref2.name, controlsEnabled = _ref2.enabled; if (keepAliveCache.current[controlsName]) { keepAliveCache.current[controlsName].enabled = controlsEnabled; } }; // Drop cache var handleDropCache = function handleDropCache(event) { var _ref3 = (event == null ? void 0 : event.detail) || {}, dropKeepAliveName = _ref3.name, scrollToTop = _ref3.scrollToTop; // If no name, drop all cache if (!dropKeepAliveName) { keepAliveCache.current = {}; } else if (typeof dropKeepAliveName === 'string') { var _keepAliveCache$curre5; (_keepAliveCache$curre5 = keepAliveCache.current) == null || delete _keepAliveCache$curre5[dropKeepAliveName]; } else if (typeof dropKeepAliveName === 'function') { var _cachesToRemove$filte; var caches = dropKeepAliveName == null ? void 0 : dropKeepAliveName(Object.keys(keepAliveCache.current)); var cachesToRemove = Array.isArray(caches) ? caches : [caches]; // eslint-disable-next-line no-unused-expressions cachesToRemove == null || (_cachesToRemove$filte = cachesToRemove.filter(function (exists) { return exists; })) == null || _cachesToRemove$filte.forEach(function (cacheName) { var _keepAliveCache$curre6; return (_keepAliveCache$curre6 = keepAliveCache.current) == null || delete _keepAliveCache$curre6[cacheName]; }); } if (scrollToTop && typeof window !== 'undefined') { window.scrollTo(0, 0); } forceUpdate({}); }; // Handle scroll position caching - requires an up-to-date router.asPath React.useEffect(function () { router.events.on('routeChangeStart', handleRouteChangeStart); router.events.on('routeChangeComplete', handleRouteChangeComplete); return function () { router.events.off('routeChangeStart', handleRouteChangeStart); router.events.off('routeChangeComplete', handleRouteChangeComplete); }; }, [router.asPath]); // Emit mounting events // @ts-ignore React.useEffect(function () { if (isKeptAlive) { window.dispatchEvent(new CustomEvent('onKeepAliveMount', { detail: name })); return function () { window.dispatchEvent(new CustomEvent('onKeepAliveUnmount', { detail: name })); }; } }, [CurrentComponent, pageProps]); /** * Listen to changes (enabled/disabled) */ React.useEffect(function () { window.addEventListener('keepAliveControls_LoadFromCache', handleLoadFromCache); window.addEventListener('keepAliveControls_DropCache', handleDropCache); return function () { window.removeEventListener('keepAliveControls_LoadFromCache', handleLoadFromCache); window.removeEventListener('keepAliveControls_DropCache', handleDropCache); }; }, []); var getCachedViewProps = function getCachedViewProps(cachedProps) { // Apply new props if (applyNewProps === true) { return pageProps; } // Apply combination of old and new props if (typeof applyNewProps === 'function') { return applyNewProps(cachedProps, pageProps); } // Apply cached props return cachedProps; }; /** * Custom useEffect which runs only when component alive. */ var getKeepAliveEffect = function getKeepAliveEffect(isHidden) { var useKeepAliveEffect = function useKeepAliveEffect(effect, deps) { return React.useEffect(function () { if (!isHidden) { return effect(); } }, deps); }; return useKeepAliveEffect; }; return ( // eslint-disable-next-line react/jsx-fragments React__default["default"].createElement(React.Fragment, null, (!isKeptAlive || !isEnabled()) && children, React__default["default"].createElement("div", { style: { display: isKeptAlive && isEnabled() ? 'block' : 'none' }, id: "keep-alive-container", "data-keepalivecontainer": true }, Object.entries(keepAliveCache.current).map(function (_ref4) { var cacheName = _ref4[0], _ref4$ = _ref4[1], Component = _ref4$.Component, cachedProps = _ref4$.pageProps; return React__default["default"].createElement("div", { key: cacheName, style: { display: name === cacheName ? 'block' : 'none' }, "data-keepalive": cacheName, "data-keepalive-hidden": name !== cacheName }, React__default["default"].createElement(Component, _extends({ isHiddenByKeepAlive: name !== cacheName, useEffect: getKeepAliveEffect(name !== cacheName) }, getCachedViewProps(cachedProps)))); }))) ); }; var defaultOpts = { keepScrollEnabled: true, applyNewProps: false }; var withKeepAlive = function withKeepAlive(Component, name, opts) { if (opts === void 0) { opts = defaultOpts; } var KeepAlive = function KeepAlive(props) { return ( // eslint-disable-next-line react/jsx-fragments React__default["default"].createElement(React.Fragment, null, React__default["default"].createElement(Component, _extends({}, props))) ); }; // Copy getInitial props so it will run as well // @ts-ignore if (Component.getInitialProps) { // @ts-ignore KeepAlive.getInitialProps = Component.getInitialProps; } var _ref = opts || {}, keepScrollEnabled = _ref.keepScrollEnabled, applyNewProps = _ref.applyNewProps; KeepAlive.keepAlive = { name: name, keepScrollEnabled: keepScrollEnabled, applyNewProps: applyNewProps }; return KeepAlive; }; /** * Hook for handling mount event * @param name * @param effect */ var useKeepAliveMountEffect = function useKeepAliveMountEffect(name, effect) { // Trigger mount var handleMountedEvent = function handleMountedEvent(e) { if ((e == null ? void 0 : e.detail) === name && typeof effect === 'function') { effect(); } }; React.useEffect(function () { window.addEventListener('onKeepAliveMount', handleMountedEvent); return function () { window.removeEventListener('onKeepAliveMount', handleMountedEvent); }; }, []); }; /** * Hook for handling unmount event * @param name * @param effect */ var useKeepAliveUnmountEffect = function useKeepAliveUnmountEffect(name, effect) { // Trigger mount var handleUnmountedEvent = function handleUnmountedEvent(e) { if ((e == null ? void 0 : e.detail) === name && typeof effect === 'function') { effect(); } }; React.useEffect(function () { window.addEventListener('onKeepAliveUnmount', handleUnmountedEvent); return function () { window.removeEventListener('onKeepAliveUnmount', handleUnmountedEvent); }; }, []); }; function keepAliveLoadFromCache(name, enabled) { if (typeof window !== 'undefined') { window.dispatchEvent(new CustomEvent('keepAliveControls_LoadFromCache', { detail: { name: name, enabled: enabled } })); } } function keepAliveDropCache(name, scrollToTop) { if (typeof window !== 'undefined') { window.dispatchEvent(new CustomEvent('keepAliveControls_DropCache', { detail: { name: name, scrollToTop: scrollToTop } })); } } exports.KeepAliveProvider = KeepAliveProvider; exports.keepAliveDropCache = keepAliveDropCache; exports.keepAliveLoadFromCache = keepAliveLoadFromCache; exports.useKeepAliveMountEffect = useKeepAliveMountEffect; exports.useKeepAliveUnmountEffect = useKeepAliveUnmountEffect; exports.withKeepAlive = withKeepAlive; //# sourceMappingURL=index.js.map