Fix <Route children>
See original GitHub issueThere was a lot of discussion in #5583 about removing the <Route children> prop and adding a new prop about when to render. The conversation in that issue stalled, so I’d like to resume it here, but with a completely different proposal.
The core issue is that it’s not very clear what the difference is between <Route children> and <Route render>. The API doesn’t really say anything about when to use one over the other.
In contrast to the proposal in #5583 (remove children and add a new prop about when to render) I’d like to propose that we just tweak the way children works and get rid of render (eventually). Here’s why:
Currently, <Route children> always renders, which doesn’t make any sense. Wanna see something crazy?
<Route path="/about" children={() => (
<About />
)} />
// or even
<Route path="/about">
<About />
</Route>
You might think these routes only render when the URL path is /about, but nope. They both will render at any URL. 🙃 This is a huge mistake in the v4 API, and I’d be very surprised if anyone is actually using <Route children> like this.
The reason this API exists is because you’re supposed to check the match prop to see if the <Route> matched before rendering anything, e.g.:
<Route path="/about" children={props => (
props.match ? <About /> : <NotFound />
)} />
So now if the URL is /about you’ll get the <About> page, otherwise <NotFound>. That at least makes a little more sense than the previous examples, and hopefully redeems us a little. But it doesn’t change the fact that the first examples are just crazy.
The vast majority of the time you want to render something only when the route matches the URL, and ignore misses. So we added the <Route render> and <Route component> APIs that will only render something when it matches. These are used much more commonly than <Route children> in all our docs and examples.
The Proposal
It’s quite simple, really: The default behavior of children should be to only render something when the route matches the URL. We don’t need any new API to <Route>, and we definitely don’t want to get rid of the children prop. We just need to fix it.
What about misses?
The majority of the time someone wants to handle a “miss”, they actually want to render a “not found” page. We actually already have great support for this inside a <Switch>:
<Switch>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route component={NotFound} />
</Switch>
For the rare use case that someone wants to render a standalone <Route> that does not match the URL, we already provide the matchPath function. If we want a component API, we can provide a lower-level component, call it a <Match>, that will just compute the match and tell you whether or not the path matched:
<Match path="/about">
{match => match ? <About /> : <NotFound />}
</Match>
Pros:
<Route children>is a lot more intuitive- Since
<Route children>would behave the same as<Route render>, we can eventually remove<Route render>(less API is almost always a good thing) - If a
<Route>always matches, it will be a lot easier to implement relative<Route>s and<Link>s (see #5127) - It should be easier (but still not super easy) to wrap a
<Route>now with your own component, since you have one less render prop to worry about
Cons:
- It is technically a breaking change for what I suspect is a very small percentage of our users
- ??
The Plan
- 4.x: Add a
<Match>component and encourage everyone who is usingchildrento render something when a<Route>doesn’t match a URL (probably a very small % of users) to use a<Match>instead. Unfortunately, there’s no easy way for us to warn users to stop usingchildrenfor non-matches. - 5.0: Make the switch so
<Route>only renders something when it matches. I would expect this to break very few apps, but hey, you never know. Also, keep therenderprop around for a while to ease the upgrade. - 5.x: Deprecate the
renderprop since it’s identical tochildrennow and warn people to just usechildreninstead.
Thoughts?
Issue Analytics
- State:
- Created 5 years ago
- Reactions:50
- Comments:25 (15 by maintainers)

Top Related StackOverflow Question
Thanks for the feedback, @bradwestfall 😃 The reason I like
children, especially in this case, is because it’s more flexible thanrenderbecause there are 2 different syntaxes for thechildrenprop in JSX.vs
Plus I’m seeing the community settle more on
childrenthanrenderas far as prop name goes (e.g. the new context API).As a rebuttal, I’d prefer to see
childrenstay overrender(and I don’t necessarily think a Twitter poll is a great way to determine an API). But yeah, the proposed changes look great to me, including the addition of a<Match>component that just gives its children the result frommatchPath.