1

Before upgrading to v6 I had this part of code, which worked as it should:

//before
return (
        <BrowserRouter>
            <Route render={(props) => (
                <div className={`layout ${themeReducer.mode}`}>
                    <Sidebar {...props}/>
                    <div className="layout__content">
                        <TopNav/>
                        <div className="layout__content-main">
                            <Switch>
                                <Route path='/' exact component={Dashboard} />
                                <Route path='/activity' component={Activity} />
                            </Switch>
                        </div>
                    </div>
                </div>
            )}/>
        </BrowserRouter>
    )

After upgrading I only changed Switch to Routes and component to element and expected it to work, but it didn't.

Error: A <Route> is only ever to be used as the child of <Routes> element, never rendered directly. Please wrap your <Route> in a <Routes>.

Tried many things, but nothing helped. How can I make it work the way it worked before the upgrading?

//after
return (
        <BrowserRouter>
            <Route render={(props) => (
                <div className={`layout ${themeReducer.mode}`}>
                    <Sidebar {...props}/>
                    <div className="layout__content">
                        <TopNav/>
                        <div className="layout__content-main">
                            <Routes>
                                <Route path='/' element={<Dashboard/>} />
                                <Route path='/activity' element={<Activity/>} />
                            </Routes>
                        </div>
                    </div>
                </div>
            )}/>
        </BrowserRouter>
    )
Nazar
  • 57
  • 7
  • The `Route` that is a direct child of `BrowserRouter` should be wrapped in `Routes`. – Jacob Smit Dec 06 '21 at 20:32
  • I'm just interested why before upgrading to v6 `Route` was outside `Switch`, but still worked – Nazar Dec 06 '21 at 21:15
  • 1
    In RRDv6 `Route` components required only a routing context *somewhere* above it in the ReactTree. The `Switch` component was only used really to switch from inclusive routing, i.e. render all matching paths, to exclusive routing, i.e. render only the first matching path. The `Routes` component replaces the `Switch`, and also pulls double duty handling the route matching. In RRDv6 all routes/paths are now always exactly matched, but you can render as many matches as you need. There just can't be anything between the `Routes` and `Route` components other than these layout/wrapper components. – Drew Reese Dec 06 '21 at 21:18

1 Answers1

2

Actually, the Route rendered by BrowserRouter needs to be wrapped in a Routes component and also render JSX on the element prop or wrap a child React component.

It appears to be a layout component so abstract it out into its own component that renders an Outlet for the nested Route components. If Sidebar isn't a function component to use the React hooks then use the hooks in the layout component and pass them as props to Sidebar as before. Note that if Sidebar previously used the history object that it was replaced by a navigate function in RRDv6.

import { Outlet, useLocation, useMatch, useNavigate } from 'react-router-dom';

const Layout = () => {
  const navigate = useNavigate();
  const location = useLocation();
  const match = useMatch();
  // ... etc....

  return (
    <div className={`layout ${themeReducer.mode}`}>
      <Sidebar 
        location={location}
        match={match}
        navigate={navigate}
        ...... etc....
      />
      <div className="layout__content">
        <TopNav/>
        <div className="layout__content-main">
          <Outlet /> // <-- nested routes render here
        </div>
      </div>
    </div>
  );
};

...

return (
  <BrowserRouter>
    <Routes>
      <Route path="/" element={<Layout />} >
        <Route index element={<Dashboard />} />
        <Route path="/activity" element={<Activity />} />
      </Route>
    </Routes>
  </BrowserRouter>
)
Drew Reese
  • 165,259
  • 14
  • 153
  • 181