React-router: Emphasize routers can only have one child

Created on 2 Nov 2016  路  13Comments  路  Source: ReactTraining/react-router

This may be written somewhere but I was trying to have multiple Match elements directly under a router and I kept getting a Reach.children.only error. Either a descriptive error or emphasis in the docs would go a long way.

Thanks! Happy to go implement a descriptive error if that's interesting to you all.

Most helpful comment

This looks like just a documentation issue for now. The v4 upgrade guide should probably include an example that shows how you can convert

<Router>
  <Route ...>
  <Route ...>
</Router>

to

<Router>
  <Switch>
    <Route ...>
    <Route ...>
  </Switch>
</Router>

so people don't get confused.

Another possible way to go could be for <Router> to just automatically render a <Switch> if it detects that all its children are <Route>s...

All 13 comments

What warning does React.Children.only give you? Because it seems weird to make our own custom warning. Maybe React's needs to be more clear.

Error: React.Children.only expected to receive a single React element child. with a not terribly useful stack trace. I think a custom warning would be useful because I think with React it's expected that the top-level component is the only one I expect that needs to be a single child; after that I expect to be able to insert siblings (to me personally anyway.)

Otherwise I think a callout in the docs/tutorial would be helpful.

Also, Provider in react redux is the same, and we don't have a custom warning there either.

A fair analogy. Never ran into it there. I just spent a few minutes tracking down why that was wrong and I thought it may be helpful to future users. I think in particular this will happen more because in with Provider your code tends to looks like:

<Provider store={store}>
  <App />
</Provider>

while with Router people may be inclined (like me) to do

<Router>
  <Match ... />
  <Match ... />
  <Match ... />
  <Match ... />
  <Miss ... />
</Router>

Perhaps we can inject a <MatchGroup> automatically if the children are all <Match> and <Miss> components?

If that doesn't introduce unexpected behavior I think that's an even better solution.

It actually introduces more expected (expecteder?) behavior, because that functions more like the <=3.0 APIs do.

I'm always wary on introducing magical behavior. Perhaps a custom React propType similar to what Matt Zabriskie wrote on his blog about enforcing a single child via propType and then giving a useful error that way?

sure, let's just make a better message, or have BrowserRouter render a <div/> around everything.

When you say better message, do you mean doing a propType or making it clearer in the documentation and leaving the code as-is?

Head's up, it looks like the example router code in the API docs for Miss doesn't have a wrapping element: https://github.com/ReactTraining/react-router/blob/v4.0.0-alpha.6/website/api/Miss.md#miss.

This looks like just a documentation issue for now. The v4 upgrade guide should probably include an example that shows how you can convert

<Router>
  <Route ...>
  <Route ...>
</Router>

to

<Router>
  <Switch>
    <Route ...>
    <Route ...>
  </Switch>
</Router>

so people don't get confused.

Another possible way to go could be for <Router> to just automatically render a <Switch> if it detects that all its children are <Route>s...

Fixed in 7e8fc1527366a56c17825789cf3dbd556cb10add

Was this page helpful?
0 / 5 - 0 ratings