question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Delegate route matching logic from <Switch> to <Route> (feature request)

See original GitHub issue

Hello,

currently you have following logic in <Switch> component:

https://github.com/ReactTraining/react-router/blob/master/packages/react-router/modules/Switch.js#L41-L60

<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;
  }

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Reactions:14
  • Comments:8 (1 by maintainers)

github_iconTop GitHub Comments

2reactions
MMeentcommented, Nov 14, 2017

I’m currently having problems with the same issue (having my own route component and not being able to say “don’t use this route”). Having a SwitchableComponent#computeMatch override check looks best to me, due to its ability to look at the props of the component via this.props.

My use case is routes that are only available when a user has certain permissions. This is currently “not easy” to “very difficult” to specify with just components.

2reactions
timdorrcommented, Sep 21, 2017

I’m not sure I’m sold on this. Re-using a property of the component seems like a good idea, but it means we are depending on the type of child given to Switch. The dirty little secret of Switch right now is that this works:

<Switch>
  <SomeComponent path="/" />
</Switch>

We basically fail gracefully if you pass a “bad” child in.

I’m also pessimistic about a hidden API surface. This should be more out in the open. Perhaps <Switch> could use a computeMatch prop that takes a function for computing the match. That is more explicit and visible.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Delegate route matching logic from <Switch> to ... - GitHub
What I want to propose is to delegate routing logic to <Route> components only. E.g. by creating static computeMatch() method and by calling ......
Read more >
Routing in ASP.NET Core - Microsoft Learn
NET Core routing is responsible for matching HTTP requests and dispatching ... It runs the delegate associated with the selected endpoint.
Read more >
Bountysource
Delegate route matching logic from to (feature request)
Read more >
Set up content tree-based routing - Xperience 13 Documentation
As defined in the previous section, a custom route is simply a controller that takes over when the request matches certain criteria. When...
Read more >
Learning Flutter's new navigation and routing system - Medium
TransitionDelegate · markForPush — displays the route with an animated transition · markForAdd — displays the route without an animated transition ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found