fix(react): support routes without a path for notfound routes, fixes #20259 (#20261)

This commit is contained in:
Ely Lucas
2020-01-21 16:12:42 -07:00
parent f971f76b4b
commit 85be000a4c
4 changed files with 41 additions and 17 deletions

View File

@ -1,6 +1,6 @@
import { RouteProps, match } from 'react-router-dom'; import { RouteProps, match } from 'react-router-dom';
export interface IonRouteData { export interface IonRouteData {
match: match<{ tab: string }> | null; match: match | null;
childProps: RouteProps; childProps: RouteProps;
} }

View File

@ -255,12 +255,23 @@ export class RouteManager extends React.Component<RouteManagerProps, RouteManage
const views: ViewItem[] = []; const views: ViewItem[] = [];
let activeId: string | undefined; let activeId: string | undefined;
const ionRouterOutlet = React.Children.only(children) as React.ReactElement; const ionRouterOutlet = React.Children.only(children) as React.ReactElement;
let foundMatch = false;
React.Children.forEach(ionRouterOutlet.props.children, (child: React.ReactElement) => { React.Children.forEach(ionRouterOutlet.props.children, (child: React.ReactElement) => {
const routeId = generateId(); const routeId = generateId();
this.routes[routeId] = child; this.routes[routeId] = child;
views.push(createViewItem(child, routeId, this.props.history.location)); views.push(createViewItem(child, routeId, this.props.history.location));
}); });
if (!foundMatch) {
const notFoundRoute = views.find(r => {
// try to find a route that doesn't have a path or from prop, that will be our not found route
return !r.routeData.childProps.path && !r.routeData.childProps.from;
});
if (notFoundRoute) {
notFoundRoute.show = true;
}
}
this.registerViewStack(id, activeId, views, routerOutlet, this.props.location); this.registerViewStack(id, activeId, views, routerOutlet, this.props.location);
function createViewItem(child: React.ReactElement<any>, routeId: string, location: HistoryLocation) { function createViewItem(child: React.ReactElement<any>, routeId: string, location: HistoryLocation) {
@ -289,6 +300,9 @@ export class RouteManager extends React.Component<RouteManagerProps, RouteManage
if (match && view.isIonRoute) { if (match && view.isIonRoute) {
activeId = viewId; activeId = viewId;
} }
if (!foundMatch && match) {
foundMatch = true;
}
return view; return view;
} }
} }
@ -360,7 +374,7 @@ export class RouteManager extends React.Component<RouteManagerProps, RouteManage
React.Children.forEach(ionRouterOutlet.props.children, (child: React.ReactElement) => { React.Children.forEach(ionRouterOutlet.props.children, (child: React.ReactElement) => {
for (const routeKey in this.routes) { for (const routeKey in this.routes) {
const route = this.routes[routeKey]; const route = this.routes[routeKey];
if (route.props.path === child.props.path) { if (typeof route.props.path !== 'undefined' && route.props.path === (child.props.path || child.props.from)) {
this.routes[routeKey] = child; this.routes[routeKey] = child;
} }
} }

View File

@ -65,6 +65,7 @@ export class View extends React.Component<ViewProps, {}> {
...value, ...value,
registerIonPage: this.registerIonPage.bind(this) registerIonPage: this.registerIonPage.bind(this)
}; };
return ( return (
<NavContext.Provider value={newProvider}> <NavContext.Provider value={newProvider}>
{this.props.children} {this.props.children}

View File

@ -13,7 +13,7 @@ export interface ViewStack {
* The holistic view of all the Routes configured for an application inside of an IonRouterOutlet. * The holistic view of all the Routes configured for an application inside of an IonRouterOutlet.
*/ */
export class ViewStacks { export class ViewStacks {
private viewStacks: { [key: string]: ViewStack | undefined } = {}; private viewStacks: { [key: string]: ViewStack | undefined; } = {};
get(key: string) { get(key: string) {
return this.viewStacks[key]; return this.viewStacks[key];
@ -31,25 +31,34 @@ export class ViewStacks {
delete this.viewStacks[key]; delete this.viewStacks[key];
} }
findViewInfoByLocation(location: HistoryLocation, viewKey?: string) { findViewInfoByLocation(location: HistoryLocation, viewKey: string) {
let view: ViewItem<IonRouteData> | undefined; let view: ViewItem<IonRouteData> | undefined;
let match: IonRouteData['match'] | null | undefined; let match: IonRouteData['match'] | null | undefined;
let viewStack: ViewStack | undefined; let viewStack: ViewStack | undefined;
if (viewKey) {
viewStack = this.viewStacks[viewKey]; viewStack = this.viewStacks[viewKey];
if (viewStack) { if (viewStack) {
viewStack.views.some(matchView); viewStack.views.some(matchView);
if (!view) {
viewStack.views.some(r => {
// try to find a route that doesn't have a path or from prop, that will be our not found route
if (!r.routeData.childProps.path && !r.routeData.childProps.from) {
match = {
path: location.pathname,
url: location.pathname,
isExact: true,
params: {}
};
view = r;
return true;
} }
} else { return false;
const keys = this.getKeys();
keys.some(key => {
viewStack = this.viewStacks[key];
return viewStack!.views.some(matchView);
}); });
} }
}
const result = { view, viewStack, match }; return { view, viewStack, match };
return result;
function matchView(v: ViewItem) { function matchView(v: ViewItem) {
const matchProps = { const matchProps = {
@ -61,7 +70,7 @@ export class ViewStacks {
if (myMatch) { if (myMatch) {
view = v; view = v;
match = myMatch; match = myMatch;
return view.location === location.pathname; return true;
} }
return false; return false;
} }