Creating routes inside a private route with react-router v6

Viewed 968

Currently using react-router-dom 6.1.1 and I'm working with a private route.

Inside this private route I usually had other routes (so that I can keep my Sidebar on them).

My code looks like this

// App.tsx

const RequireAuth: React.FC<PrivateRouteProps> = ({ children, redirectTo }) => {
  const isAuthenticated = Auth.isLogedIn()
  return isAuthenticated ? children : <Navigate to={redirectTo} />
}

const Page = () => {
  return (
    <div className={css.host}>
      <BrowserRouter>
        <Routes>
          <Route path="/login" element={<Login />} />

          <Route
            path="/"
            element={
              <RequireAuth redirectTo="/login">
                <Home />
              </RequireAuth>
            }
          />
        </Routes>
      </BrowserRouter>
    </div>
  )
}
// Home/index.tsx

const Home = () => {
  return (
    <div className={css.host}>
      <Sidebar sections={sidebarOptions(t)} />

      <Routes>
        {routes.map(({ breadCrumbtitle, link, component }, index) => (
          <Route path={link} key={index}>
            {component ? component : <p>[{breadCrumbtitle}] To be done</p>}
          </Route>
        ))}
      </Routes>
    </div>
  )
}

So... This setup worked with v5 but it seems to be something that doesn't really work with v6. What can I do if I still want to keep the Sidebar for all the routes once I'm logged in?

2 Answers

I ended up finding the solution to my issue. Doing what Drew Reese suggested only worked to a certain point since I was being led to a route that, for react router, didn't exist.

For it to work I add to do

// App.tsx

const RequireAuth: React.FC<PrivateRouteProps> = ({ children, redirectTo }) => {
  const isAuthenticated = Auth.isLogedIn()
  return isAuthenticated ? children : <Navigate to={redirectTo} />
}

const Page = () => {
  return (
    <div className={css.host}>
      <BrowserRouter>
        <Routes>
          <Route path="/login" element={<Login />} />

          <Route
            path=""
            element={
              <RequireAuth redirectTo="/login">
                <Home />
              </RequireAuth>
            }
          >
            {routes.map(({ breadCrumbtitle, link, component }, index) => {
              return <Route path={link} key={index} element={component}></Route>
            })}
          </Route>
        </Routes>
      </BrowserRouter>
    </div>
  )
}
// Home/index.tsx

const Home = () => {
  return (
    <div className={css.host}>
      <Sidebar sections={sidebarOptions(t)} />

      <div className={css.contentContainer}>
        <Outlet />
      </div>
    </div>
  )
}

Using the Outlet seemed to be essential, don't know if it's something new on react router v6 but seemed to do the trick!

As far as I can tell the only issue is with the routes mapping, the Route components have invalid children, i.e. you are rendering another Route or React.Fragment as a child.

Move this up to the element prop of the mapped Route components.

const Home = () => {
  return (
    <div className={css.host}>
      <Sidebar sections={sidebarOptions(t)} />
      <Routes>
        {routes.map(({ breadCrumbtitle, link, component }, index) => (
          <Route
            path={link}
            key={index}
            element={component || <p>[{breadCrumbtitle}] To be done</p>}
          />
        ))}
      </Routes>
    </div>
  );
};

Edit creating-routes-inside-a-private-route-with-react-router-v6

Related