UNPKG

react-view-router

Version:
514 lines 21.9 kB
import "core-js/modules/es6.symbol.js"; import "core-js/modules/es7.object.get-own-property-descriptors.js"; import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties"; import _slicedToArray from "@babel/runtime/helpers/slicedToArray"; import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator"; import _defineProperty from "@babel/runtime/helpers/defineProperty"; var _excluded = ["children"]; import _regeneratorRuntime from "@babel/runtime/regenerator"; function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } import "core-js/modules/es6.regexp.constructor.js"; import "core-js/modules/es6.array.filter.js"; import "core-js/modules/es7.array.includes.js"; import React, { useState, useEffect } from 'react'; import { renderRoute, normalizeRoute, isFunction, isRouteChanged, isRoutesChanged, isPropChanged, nextTick, isMatchedRoutePropsChanged, getHostRouterView, warn, hasOwnProp, getRouteChildren, ignoreCatch } from './util'; import { computeRootMatch } from './match-path'; import { RouterContext, RouterViewContext } from './context'; import KeepAlive from './keep-alive'; function normalizeRouterViewProps(props) { if (props.beforeEach && !hasOwnProp(props.beforeEach, 'global')) props.beforeEach.global = true; if (props.afterEach && !hasOwnProp(props.afterEach, 'global')) props.afterEach.global = true; } export function _checkActivate(router, matchedRoute, event) { if (!matchedRoute || !router) return; var path1 = router.basenameNoSlash + matchedRoute.path; var path2 = event.router.basenameNoSlash + event.target.path; return path1 === path2; } export function _checkDeactivate(router, matchedRoute, event) { if (!matchedRoute || !router) return; var path1 = router.basenameNoSlash + matchedRoute.path; var path2 = event.router.basenameNoSlash + event.target.path; return path1.startsWith(path2); } class RouterView extends React.Component { constructor(props) { super(props); _defineProperty(this, "_updateRef", ref => { var _this$_kaRef; var currentRoute = this.state.currentRoute; if (currentRoute) currentRoute.componentInstances[this.name] = ref; if (this.props && this.props._updateRef) this.props._updateRef(ref); if ((_this$_kaRef = this._kaRef) !== null && _this$_kaRef !== void 0 && _this$_kaRef.activeNode) this._kaRef.activeNode.instance = ref; // if (this._isMounted) this.setState({ currentRoute }); }); _defineProperty(this, "_updateKARef", ref => { if (!ref && this._kaRef && !this.isNull(this.state.currentRoute)) { ref = this._kaRef; } this._kaRef = ref; }); _defineProperty(this, "_kaActivate", event => { var _this$state = this.state, parentRoute = _this$state.parentRoute, router = _this$state.router; if (_checkActivate(router, parentRoute, event)) { this._isActivate = true; this._refreshCurrentRoute(); } }); _defineProperty(this, "_kaDeactivate", event => { var _this$state2 = this.state, parentRoute = _this$state2.parentRoute, router = _this$state2.router; if (_checkDeactivate(router, parentRoute, event)) { this._events.deactivate.forEach(e => ignoreCatch(e)(event)); this._isActivate = false; } }); this.target = new.target; this.isRouterViewInstance = true; var _router = props && props.router; var depth = props && props.depth ? Number(props.depth) : 0; var state = { _routerRoot: true, parent: null, depth, inited: false, resolving: false, router: _router, parentRoute: null, currentRoute: null, toRoute: null, routes: [], renderKeepAlive: false, enableKeepAlive: false }; this.state = state; this._isMounted = false; this._isActivate = true; this._kaRef = null; this._events = { activate: [], deactivate: [] }; normalizeRouterViewProps(props); } get name() { var name = this.props.name; if (!name) return 'default'; return name; } get currentRef() { var currentRoute = this.state.currentRoute; return currentRoute && currentRoute.componentInstances[this.name]; } get isActivate() { if (!this._isActivate) return false; var _this$state3 = this.state, _routerRoot = _this$state3._routerRoot, router = _this$state3.router; if (_routerRoot) { if (router !== null && router !== void 0 && router.basename) { var parent = getHostRouterView(this); if (parent) return parent.isActivate; } } return true; } _checkEnableKeepAlive() { var key = 'keepAlive'; if (this._kaRef) return true; if (hasOwnProp(this.props, key)) return true; var _this$state4 = this.state, currentRoute = _this$state4.currentRoute, router = _this$state4.router; if (hasOwnProp(currentRoute === null || currentRoute === void 0 ? void 0 : currentRoute.config, key)) return true; var keepAliveProps = router === null || router === void 0 ? void 0 : router.options.keepAlive; if (isFunction(keepAliveProps) || keepAliveProps instanceof RegExp) return true; return false; } _filterRoutes(routes, state) { var _this$props = this.props, name = _this$props.name, filter = _this$props.filter; var ret = routes && routes.filter(r => { var hasName = name && name !== 'default'; if (r.redirect || r.index) return hasName ? name === r.name : !r.name; return hasName ? r.components && r.components[name] : r.component || r.components && r.components.default; }); if (filter) ret = filter(ret, state || this.state); return ret; } getMatchedRoute(route, depth = 0) { var matched = (route === null || route === void 0 ? void 0 : route.matched) || []; return matched.length > depth ? matched[depth] : null; } isKeepAliveRoute(currentRoute, toRoute, router) { var _router2; if (!router) router = this.state.router; if (!currentRoute) return false; var checkKeepAlive = v => { if (isFunction(v)) v = v(currentRoute, toRoute, { router: router, view: this }); return v instanceof RegExp ? toRoute ? v.test(toRoute.path) : false : isFunction(v) ? v : Boolean(v); }; var keepAlive = currentRoute.config.keepAlive; if (keepAlive) return checkKeepAlive(keepAlive); keepAlive = this.props.keepAlive; if (keepAlive) return checkKeepAlive(keepAlive); keepAlive = (_router2 = router) === null || _router2 === void 0 ? void 0 : _router2.options.keepAlive; return isFunction(keepAlive) ? checkKeepAlive(keepAlive) : false; } _refreshCurrentRoute(state, pendingState, callback) { if (!state) state = this.state; var router = state.router; if (!router) throw new Error('state.router is null!'); var currentRoute = this.state.currentRoute; var toRoute = this.getMatchedRoute(router.currentRoute, state.depth); if (!toRoute) { var _route = normalizeRoute({ path: '' }, state.parentRoute && state.parentRoute.config); toRoute = router.createMatchedRoute(_route, computeRootMatch()); router.currentRoute && router.currentRoute.matched.push(toRoute); } else if (!toRoute || toRoute.redirect) toRoute = null; var isChanged = isRouteChanged(currentRoute, toRoute); var isMounted = this._isMounted; var newState = { enableKeepAlive: this.state.enableKeepAlive || this._checkEnableKeepAlive(), currentRoute: toRoute }; if (toRoute) toRoute.viewInstances[this.name] = this; if (isMounted && isChanged && router.options.keepAlive) { var _event = { router, source: this, target: null, to: toRoute, from: currentRoute }; newState.renderKeepAlive = this.isKeepAliveRoute(currentRoute, toRoute, router); var kaRef = this._kaRef; if (kaRef) { var _toRoute2; if (newState.renderKeepAlive) { if ((currentRoute === null || currentRoute === void 0 ? void 0 : currentRoute.path) === kaRef.activeName) { var _activeNode$instance; _event.target = currentRoute; this._events.deactivate.forEach(e => ignoreCatch(e)(_event)); var activeNode = kaRef.activeNode; (activeNode === null || activeNode === void 0 || (_activeNode$instance = activeNode.instance) === null || _activeNode$instance === void 0 ? void 0 : _activeNode$instance.componentWillUnactivate) && ignoreCatch(activeNode.instance.componentWillUnactivate.bind(activeNode.instance))(); } } else if (currentRoute) { var _toRoute; kaRef.remove(currentRoute.path, ((_toRoute = toRoute) === null || _toRoute === void 0 ? void 0 : _toRoute.path) === currentRoute.path); } var toPath = (_toRoute2 = toRoute) === null || _toRoute2 === void 0 ? void 0 : _toRoute2.path; if (toPath && kaRef.activeName !== toPath) { var toNode = kaRef.find(toPath); if (toNode) { var beforeActivate = toNode.beforeActivate || this.props.beforeActivate || router.options.beforeViewActivate; if (!beforeActivate || beforeActivate(currentRoute, toRoute, { view: this, router })) { _event.target = toRoute; nextTick(() => { var _toNode$instance; if (!this._isMounted) return; if ((_toNode$instance = toNode.instance) !== null && _toNode$instance !== void 0 && _toNode$instance.componentDidActivate) ignoreCatch(toNode.instance.componentDidActivate.bind(toNode.instance))(); this._events.activate.forEach(e => ignoreCatch(e)(_event)); }); } } } } } if (this.state.inited) { if (pendingState) Object.assign(pendingState, newState);else if (isMounted) { var currentRef = this.currentRef; if (isChanged && !newState.renderKeepAlive && currentRef && router._isReactViewComponent(currentRef)) { currentRef._willUnmount(); } try { this.setState(newState); } catch (ex) { console.error(ex); } var onRouteChange = this.props.onRouteChange; if (isChanged && onRouteChange) ignoreCatch(onRouteChange)(toRoute, currentRoute); } } else if (state !== this.state) Object.assign(state, newState); if (isMounted) callback && callback(); return toRoute; } _updateResolving(resolving, toRoute = null) { if (!this._isMounted) return; this.setState({ resolving, toRoute }); } _resolveFallback() { var ret = null; var fallback = this.props.fallback; if (isFunction(fallback)) { var _this$state5 = this.state, parentRoute = _this$state5.parentRoute, currentRoute = _this$state5.currentRoute, toRoute = _this$state5.toRoute, inited = _this$state5.inited, resolving = _this$state5.resolving, depth = _this$state5.depth, router = _this$state5.router; ret = fallback({ parentRoute, currentRoute, toRoute, inited, resolving, depth, router, view: this }); } else if (/*#__PURE__*/React.isValidElement(fallback)) ret = fallback; return ret || null; } isNull(route) { return !route || !route.path || route.subpath === '' || route.isNull; } componentDidMount() { var _this = this; return _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee() { var _parent; var state, router, parent, parentRouter, _parent$_events, _parent$_events2, pendingRoute, _ref, _ref2, location, _router3; return _regeneratorRuntime.wrap(function (_context) { while (1) switch (_context.prev = _context.next) { case 0: _this._isMounted = true; if (!_this.state.inited) { _context.next = 1; break; } return _context.abrupt("return"); case 1: if (!(!_this._reactInternalFiber && !_this._reactInternals)) { _context.next = 2; break; } return _context.abrupt("return"); case 2: state = _objectSpread({}, _this.state); router = state.router; parent = getHostRouterView(_this); parentRouter = (_parent = parent) === null || _parent === void 0 ? void 0 : _parent.state.router; if (router && parent) { if (!parentRouter || router.mode !== parentRouter.mode || !router.basename) parent = null; } if (parent) { state.parent = parent; (_parent$_events = parent._events) === null || _parent$_events === void 0 || _parent$_events.activate.push(_this._kaActivate); (_parent$_events2 = parent._events) === null || _parent$_events2 === void 0 || _parent$_events2.deactivate.unshift(_this._kaDeactivate); } if (!(router && (!parent || parentRouter !== router))) { _context.next = 3; break; } if (!router.isRunning) { warn('[RouterView]warning: router is not running.'); } router.viewRoot = _this; pendingRoute = router.pendingRoute; router.pendingRoute = null; state.routes = _this._filterRoutes(router.routes); _ref = router.history.getIndexAndLocation ? router.history.getIndexAndLocation() : [router.history.index, router.history.location], _ref2 = _slicedToArray(_ref, 2), location = _ref2[1]; router._handleRouteInterceptor(pendingRoute || _objectSpread({}, location), (ok, to) => { if (!ok) return; router && to && router.updateRoute(to); _this._refreshCurrentRoute(state); if (isFunction(ok)) ok(true, router.currentRoute); if (_this._isMounted) _this.setState(Object.assign(state, { inited: _this._isMounted })); }, true); _context.next = 5; break; case 3: state._routerRoot = false; if (parent) { _context.next = 4; break; } throw new Error('[RouterView] cannot find root RouterView instance!'); case 4: if (!router) router = state.router = parent.state.router; state.depth = parent.state.depth + 1; state.parentRoute = _this.getMatchedRoute((_router3 = router) === null || _router3 === void 0 ? void 0 : _router3.currentRoute, state.depth - 1); state.routes = state.parentRoute ? _this._filterRoutes(getRouteChildren(state.parentRoute.config.children, state.parentRoute.config)) : []; _this._refreshCurrentRoute(state); if (_this._isMounted) _this.setState(Object.assign(state, { inited: true })); case 5: case "end": return _context.stop(); } }, _callee); }))(); } componentWillUnmount() { this._isMounted = false; var _this$state6 = this.state, _routerRoot = _this$state6._routerRoot, parent = _this$state6.parent, router = _this$state6.router; if (parent) { var removeEvent = (name, fn) => { if (!parent._events) return; var events = parent._events[name]; var idx = events.indexOf(fn); if (~idx) events.splice(idx, 1); }; removeEvent('activate', this._kaActivate); removeEvent('deactivate', this._kaDeactivate); } _routerRoot && router && (router.viewRoot = null); } shouldComponentUpdate(nextProps, nextState) { if (!this._isMounted) return false; if (this.state.resolving !== nextState.resolving) return true; if (this.state.inited !== nextState.inited) return true; if (this.state.depth !== nextState.depth) return true; if (this.state.router !== nextState.router) return true; var router = nextState.router; if (isPropChanged(this.props, nextProps, (key, val, oldVal) => { if (key === 'fallback' && nextState.resolving) return false; if (key === 'keepAlive' && isFunction(val) && isFunction(oldVal)) return false; if (['onRouteChange', 'beforeEach', 'afterEach', 'filter', 'beforeActivate'].includes(key)) return false; return true; })) return true; if (isRouteChanged(this.state.currentRoute, nextState.currentRoute)) return true; if (isRoutesChanged(this.state.routes, nextState.routes)) return true; if (router && isMatchedRoutePropsChanged(this.state.currentRoute, router, this.name)) return true; return false; } static getDerivedStateFromProps(nextProps) { normalizeRouterViewProps(nextProps); return null; } getComponentProps() { var _this$props2 = this.props, children = _this$props2.children, props = _objectWithoutProperties(_this$props2, _excluded); var excludeProps = this.target.defaultProps.excludeProps || RouterView.defaultProps.excludeProps || []; excludeProps.forEach(key => delete props[key]); return { props, children }; } getComponent(currentRoute) { if (!currentRoute) return null; var _this$state7 = this.state, routes = _this$state7.routes, router = _this$state7.router; var _ref3 = router && router.currentRoute || {}, _ref3$query = _ref3.query, query = _ref3$query === void 0 ? {} : _ref3$query, _ref3$params = _ref3.params, params = _ref3$params === void 0 ? {} : _ref3$params; var _this$getComponentPro = this.getComponentProps(), children = _this$getComponentPro.children, props = _this$getComponentPro.props; return renderRoute(currentRoute, routes, props, children, { router, name: this.name, query, params, ref: this._updateRef }); } renderCurrent(currentRoute) { if (this.isNull(currentRoute)) return this.props.children || null; return this.getComponent(currentRoute); } renderContainer(current, currentRoute) { var _this$state8 = this.state, routes = _this$state8.routes, router = _this$state8.router, depth = _this$state8.depth; var container = this.props.container; if (router) { container = router._callEvent('onViewContainer', container, { routes, route: currentRoute, depth, router, view: this }) || container; } return container && currentRoute ? container(current, currentRoute, current && current.props || this.getComponentProps(), this) : current; } render() { if (!this.state.inited) return this._resolveFallback(); var router = this.state.router; if (!router) return null; var _this$state9 = this.state, currentRoute = _this$state9.currentRoute, _routerRoot = _this$state9._routerRoot, resolving = _this$state9.resolving, renderKeepAlive = _this$state9.renderKeepAlive, enableKeepAlive = _this$state9.enableKeepAlive; var renderUtils = router.options.renderUtils; var ret = this.renderCurrent(currentRoute); if (enableKeepAlive && renderUtils) { var activeName = currentRoute ? currentRoute.path : ''; var extra = {}; if (isFunction(renderKeepAlive)) extra.beforeActivate = renderKeepAlive; ret = /*#__PURE__*/React.createElement(KeepAlive, Object.assign({ utils: renderUtils, activeName, anchorName: `${router.mode}:${router.basenameNoSlash}:${activeName}`, ref: this._updateKARef, extra }), ret); } ret = this.renderContainer(ret, currentRoute); ret = /*#__PURE__*/React.createElement(RouterViewContext.Provider, { value: this }, ret); if (_routerRoot) { ret = /*#__PURE__*/React.createElement(RouterContext.Provider, { value: router }, ret); } ret = /*#__PURE__*/React.createElement(React.Fragment, {}, ret, resolving ? this._resolveFallback() : null); return ret; } } var RouterViewWrapper = /*#__PURE__*/React.forwardRef((props, ref) => { var _useState = useState(!props.router || props.router.isRunning), _useState2 = _slicedToArray(_useState, 2), isRunning = _useState2[0], setIsRunning = _useState2[1]; useEffect(() => { if (!isRunning && props.router && props.router.isRunning) { setIsRunning(true); } }, // eslint-disable-next-line react-hooks/exhaustive-deps [isRunning, props.router && props.router.isRunning]); return isRunning ? /*#__PURE__*/React.createElement(RouterView, _objectSpread(_objectSpread({}, props), {}, { _updateRef: ref && (isFunction(ref) ? ref : r => ref.current = r) })) : null; }); RouterView.defaultProps = { excludeProps: ['_updateRef', 'name', 'filter', 'fallback', 'container', 'router', 'depth', 'excludeProps', 'beforeEach', 'afterEach', 'onRouteChange', 'keepAlive'] }; export { RouterViewWrapper, RouterView as RouterViewComponent }; export default RouterViewWrapper; //# sourceMappingURL=router-view.js.map