-
-
Notifications
You must be signed in to change notification settings - Fork 10.8k
Description
Hello,
currently you have following logic in <Switch> component:
<Switch> component makes assumption, that it will always receive the 'whatever' component, but with the specific options (path, exact, etc).
What the bad here is that if you'll want to wrap <Route> component in HOC with a different props interface, this new <HocRoute> won't work with <Switch> anymore, because <Switch> has its own copy-pasted matching logic and it, actually routes and only then switches.
What I want to propose is to delegate routing logic to <Route> components only. E.g. by creating static computeMatch() method and by calling element.type.computeMatch(props, router) instead of calling matchPath() on props, that do not belong to <Switch> component.
I know, that element.type is a little bit hacky, but this will allow a great composability and extendability of react-router.
The use cases
Named routes
You can implement something like this:
<NamedRoute name="home" component={HomePage} />import { Route } from 'react-router-dom';
const routes = {
home: '/'
};
class NamedRoute extends Component // or it can be extends Route too {
static computeMatch({ name, ...rest }, router) {
const path = routes[name] || '/';
return Route.computeMatch({ path, ...rest }, router);
}
render() {
return <Route {...this.props} />;
}
}Route aliasing
<Route aliases={['/', '/index']} component={HomePage} />import { Route, Switch } from 'react-router-dom';
class AliasRoute extends Component {
static computeMatch({ aliases, ...rest }, router) {
// btw. the alias can be the whole object
// with props for Route instead of only path
return aliases.reduce((match, path) => {
if (match) {
return match;
}
return Route.computeMatch({ path, ...rest }, router);
}, null);
}
render() {
const { aliases, ...rest } = this.props;
return (
<Switch>
{aliases.map((path) => (
<Route path={path} {...rest} />
))}
</Switch>
);
}
}This component can actually solve another <Switch> nesting problem, but the actual <Switch> component is hidden inside <AliasRoute>.
Switch nesting
The <Switch> can actually implement computeMatch() too and allow nesting:
static computeMatch({ children, location }, router) {
let match = null;
React.Children.forEach(children, (child) => {
if (match) {
return true;
}
match = child.type.computeMatch({location, ...child.props}, router);
});
return match;
}