Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove support for nested absolute routes #3172

Closed
taion opened this issue Mar 11, 2016 · 18 comments
Closed

Remove support for nested absolute routes #3172

taion opened this issue Mar 11, 2016 · 18 comments

Comments

@taion
Copy link
Contributor

taion commented Mar 11, 2016

What do we think about dropping support for having nested routes with absolute paths? This will simplify route matching and remove the annoying inconsistency between sync and async routes, and will make support for things like condition per #3098 nicer.

If we look at the motivating example from https://github.com/reactjs/react-router/blob/v2.0.1/docs/guides/RouteConfiguration.md#decoupling-the-ui-from-the-url:

render((
  <Router>
    <Route path="/" component={App}>
      <IndexRoute component={Dashboard} />
      <Route path="about" component={About} />
      <Route path="inbox" component={Inbox}>
        {/* Use /messages/:id instead of messages/:id */}
        <Route path="/messages/:id" component={Message} />
      </Route>
    </Route>
  </Router>
), document.body)

We could better write this as:

render((
  <Router>
    <Route path="/" component={App}>
      <IndexRoute component={Dashboard} />
      <Route path="about" component={About} />
      <Route component={Inbox}>
        <Route path="inbox" />
        <Route path="messages/:id" component={Message} />
      </Route>
    </Route>
  </Router>
), document.body)

And in general I believe this sort of pattern is going to be possible – and it just makes it more clear that matching can only continue down routes that either actually match or are path-less.

@taion taion changed the title Remove support for decoupling UI from the URL Remove explicit support for decoupling UI from the URL Mar 11, 2016
@taion taion changed the title Remove explicit support for decoupling UI from the URL Remove support for nested absolute routes Mar 11, 2016
@ryanflorence
Copy link
Member

This was one of the primary use-cases that led me to creating react router. A previous router wouldn't let me do it, or at least I couldn't figure out how to, and I had to say "no" to our product team who wanted some urls that weren't nested.

Though, now that I type that, I wonder if this could work ...

<Route path="/" component={App}>
  <Route path="inbox" component={Inbox}/>
  <Route component={Inbox}>
    <Route path="messages/:id" component={Message} />
  </Route>
</Route>

Message is still nested beneath Inbox but has its own url.

Interesting ... I think I'm okay with that if it makes the matching code faster, easier to add new features to, or prevents bugs we can anticipate.

But, I'm not okay with it if it's just something that makes us as programmers sleep better at night knowing our matching algorithm is less complex.

@taion
Copy link
Contributor Author

taion commented Mar 11, 2016

@ryanflorence

I think the second example I give in the OP is better, in that it doesn't duplicate component={Inbox}.

The main benefit from a code hygiene perspective is that it makes our route matching work in a much more intuitive way – specifically, we don't end up traversing down all possible routes, including ones that don't match, just because they might have nested absolute children.

The proximate motivation is to let us move forward with #3098 – at the moment, this has the potential to work in an extremely unintuitive and unpleasantly surprising way, since we keep following down routes that already haven't matched.

@ryanflorence
Copy link
Member

Ah, I missed that in your comment, that does look good. It's way less intuitive for end-users, but in the case of async routing we would probably be saving a lot of network activity as well by simplifying the matching.

(Sorry for missing that, I'm actually making a github.com/notifications replacement, and it just hit the "almost useful" stage so I commented :P)

@taion
Copy link
Contributor Author

taion commented Mar 11, 2016

For the good the async case, to minimize going down branches that won't eventually lead to a match, something like what you have is actually better, though you'd probably want to pivot it a bit like:

<Route path="/" component={App}>
  <Route path="inbox" component={Inbox} />
  <Route path="messages/:id" component={Inbox}>
    <IndexRoute component={Message} />
  </Route>
</Route>

But per #2244, nested absolute routes don't work with async routes anyway, so whatever we do here has no bearing on how users of async routes handle things.

Anyway, given that my PR to replace our route matching with path-to-regexp (#3105) – and more broadly any substantive changes to how we define path strings – is blocked on figuring out how we want to want to warn for unreachable routes (#1923), the only way to move forward on user-customizable route matching (#2286) is via adding a per-route binary check (#3098), but that check is going to work in a really unintuitive way without this change.

@timdorr
Copy link
Member

timdorr commented Mar 11, 2016

I'm also for this. I think it's actually more confusing to the end user that they can create paths that don't match the layout of their route tree. You can always make that route structure work in another way anyways, even if it's a bit more verbose.

@taion Dude, your issue reference game is on point today 😆

@johanneslumpe
Copy link
Contributor

@taion I think it's valid to remove support for this. When I originally posted #2244 I thought it might be a good idea since the router supported paths which broke out of their nested structure. Since then I actually never needed this and @timdorr has a good point on it being more confusing.

I'm wondering if a lot of people depend on being able to use nested absolute routes in general. If not, then I'm all for removing this.

@ryanflorence
Copy link
Member

My hunch is that it's not used that often, and since we can create the same paths with the components with some finessing around route config, I'm happy to forward. @mjackson, thoughts?

@mjackson
Copy link
Member

I'm actually really optimistic about this. Nested absolute routes are one feature that really prevented me from simplifying the implementation a lot. It's been a while since I've loaded it all into my head, but I think there are some really cool things we can do if we get rid of that constraint.

However, as @ryanflorence said, we absolutely need the ability to nest UI at "root" URLs. That was the whole motivation behind the shared-root example in the first place. The decoupling of route nesting from URL nesting is something I'm not willing to part with.

I'll think about this over the next few days, but I'm optimistic we can move forward here. Seems like we can just juggle things around in the route config w/o nested absolute paths to make any scenario that is possible with them.

@ryanflorence
Copy link
Member

Seems like we can just juggle things around in the route config w/o nested absolute paths to make any scenario that is possible with them.

Yeah, I was screwing around the other day and I couldn't figure out a scenario that isn't possible.

DELETING CODE IS THE BEST

@taion
Copy link
Contributor Author

taion commented Mar 13, 2016

The simple scenario above is easy to deal with. The trickier one is something like:

<Route path="foo" component={Foo}>
  <Route path="bar" component={Bar}>
    <Route path="/baz" component={Baz} />
  </Route>
</Route>

I think you end up having to declare this as something like:

<Route component={Foo}>
  <Route path="foo" />
  <Route component={Bar}>
    <Route path="foo/bar" />
    <Route path="baz" component={Baz} />
  </Route>
</Route>

Or else:

<Route component={Foo}>
  <Route path="foo">
    <Route path="bar" component={Bar} />
  </Route>
  <Route component={Bar}>
    <Route path="baz" component={Baz} />
  </Route>
</Route>

In other words, there's no way to do this without some duplication, either in path or in component definitions.

But IMO this example is contrived, and to do this in the first place is just confusing – plus I've demonstrated workarounds here anyway.

@taion
Copy link
Contributor Author

taion commented Mar 14, 2016

Anyway, the only actionable thing here is to add a warning.

@ryanflorence
Copy link
Member

Second example is how I'd do it, and document it, there really isn't any "duplication", it just seems like there is. It's actually more clear than a magical / I think.

@mjackson
Copy link
Member

What would be really nice is if we had a build step for route configs.
Then, we could generate code in scenarios like this, instead of telling
users to do it themselves/putting it in the docs.

On Mon, Mar 14, 2016 at 9:22 AM Ryan Florence [email protected]
wrote:

Second example is how I'd do it, and document it, there really isn't any
"duplication", it just seems like there is. It's actually more clear than a
magical / I think.


Reply to this email directly or view it on GitHub
#3172 (comment)
.

@taion
Copy link
Contributor Author

taion commented Mar 14, 2016

I don't think having something like a build step is possible in general – getChildRoutes currently supports doing fully dynamic things, so we can't know statically what the routes are.

@mjackson
Copy link
Member

It absolutely is- just need to think outside of the paradigm we're
currently working in :)

I'm thinking more along the lines of a bundler plugin (probably start w
webpack) that can analyze your route config and generate all those config
objects. Asking users to programmatically configure the router is tedious.

On Mon, Mar 14, 2016 at 9:41 AM Jimmy Jia [email protected] wrote:

I don't think having something like a build step is possible in general –
getChildRoutes currently supports doing fully dynamic things, so we can't
know statically what the routes are.


Reply to this email directly or view it on GitHub
#3172 (comment)
.

@taion
Copy link
Contributor Author

taion commented Mar 14, 2016

That's not what I mean. getChildRoutes is an opaque function that can return literally anything. It doesn't even need to be deterministic.

Maybe I'm misunderstanding what you mean. What is your preferred API for defining the route configuration above?

@taion
Copy link
Contributor Author

taion commented May 5, 2016

Heads-up: I plan to close this issue and open a new issue describing an updated proposal when I have a chance. The idea will be to move more of the route matching logic into routes themselves, and allow configuring this sort of behavior on a route-by-route basis. This is inspired by @ryanflorence's examples with self-rendering routes.

@taion taion mentioned this issue Jul 5, 2016
8 tasks
@taion
Copy link
Contributor Author

taion commented Jul 5, 2016

Folded into #3611.

@taion taion closed this as completed Jul 5, 2016
@lock lock bot locked as resolved and limited conversation to collaborators Jan 21, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants