Home > Back-end >  React Router v6 : How to render multiple component inside and outside a div with the same path
React Router v6 : How to render multiple component inside and outside a div with the same path

Time:02-20

I'm trying to upgrade to react-router-dom v6 :

v5

In version 5 it works like a charm:

App.js

import Sidebar from "./components/sidebar/Sidebar";
import Topbar from "./components/topbar/Topbar";
import "./app.css";
import Home from "./pages/home/Home";
import {
  BrowserRouter as Router,
  Switch,
  Route,
} from "react-router-dom";
import UserList from "./pages/userList/UserList";
import User from "./pages/user/User";
import NewUser from "./pages/newUser/NewUser";
import ProductList from "./pages/productList/ProductList";
import Product from "./pages/product/Product";
import NewProduct from "./pages/newProduct/NewProduct";
import Login from "./pages/login/Login";



function App() {

   const admin = JSON.parse(JSON.parse(localStorage.getItem("persist:root"))?.user || "{}")?.currentUser?.isAdmin ;

  return (
    <Router>
    <Switch>
      <Route path="/login">
        <Login />
      </Route>
      {admin && (
        <>
          <Topbar />
          <div className="container">
            <Sidebar />
            <Route exact path="/">
              <Home />
            </Route>
            <Route path="/users">
              <UserList />
            </Route>
            <Route path="/user/:userId">
              <User />
            </Route>
            <Route path="/newUser">
              <NewUser />
            </Route>
            <Route path="/products">
              <ProductList />
            </Route>
            <Route path="/product/:productId">
              <Product />
            </Route>
            <Route path="/newproduct">
              <NewProduct />
            </Route>
          </div>
        </>
      )}
    </Switch>
  </Router>
  );
}

export default App;

v6

When upgraded to v6 I changed my code to be like this:

<Routes>
  <Route path="/login" element={<Login />} />
  {admin && (
    <>
      <Route path="/" element={<Topbar />}/>
      <Route path="/" element={
        <>
          <div className="container">
            <Route index element={<Sidebar/>}/>
            <Route index element={<Home/>}/>
            <Route path="/users" element={<UserList />} />
            <Route path="/user/:userId" element={<User />} />
            <Route path="/newUser" element={<NewUser />} />
            <Route path="/productList" element={<ProductList />} />
            <Route path="/product/:productId" element={<Product />} /> 
            <Route path="/newProduct" element={<NewProduct />} />
          </div>
        </> 
      }
    </>
  )}
</Routes>

This is my css file for App.js

Notice: the Topbar component should be outside the div, and react router didn't recognize the components inside the as routes even without div, that means each component should have a unique path, I tried also two components with the same path like this:

<Route path="/" element = {<><Home/><Sidebar/><>}, but the css is not taking effect

.container {
  display: flex;
  margin-top: 50px;
}

It doesn't work. I tried different code and I searched a lot without finding any solution.

CodePudding user response:

I will share working code from my project, hope this will help you.

Try to create a component layout that should look something like this:

// Layout.js
import React from "react";
import { NavBar } from "./SidebarNav";
export const Layout = ({ children }) => {
  return (
    <>
      <div className="block">
        <NavBar />
        <div className="w-full ">{children}</div>
      </div>
    </>
  );
};

and then create routes in a similar way:

// routes.js
import { Routes, Route } from "react-router-dom";
import { Layout } from "./layout/Layout";
import Home from "./pages/Home";
import { ItemList } from "./pages/ItemList";

const BaseRouter = () => (
  <>
    <Layout>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/item-list/" element={<ItemList />} />
      </Routes>
    </Layout>
  </>
);

export default BaseRouter;

Splitting routes into a separate file gives you more freedom and, above all, makes your code more accessible.

// App.js
import { BrowserRouter as Router } from "react-router-dom";
import BaseRouter from "./routes";

function App() {
  return (
    <Router>
      <BaseRouter />
    </Router>
  );
}

export default App;

CodePudding user response:

Part of the issue is that you are rendering multiple identical paths, i.e. two "/" paths and two nested index paths. This won't work.

In react-router-dom v6 you can create what are called layout components. The layout components can render your headers and footers, sidebars, drawers, and general content layout elements, and importantly an Outlet component for the nested/wrapped Route components to be rendered into.

Example:

import { Outlet } from 'react-router-dom';

const AppLayout = ({ admin }) => admin ? (
  <>
    <Topbar />
    <div className="container">
      <Sidebar />
      <Outlet />
    </div>
  </>
) : null;

Render the layout component into a Route wrapping the routes you want to be rendered into the specific layout.

<Routes>
  <Route path="/login" element={<Login/>} />
  <Route element={<AppLayout admin={admin} />}>
    <Route index element={<Home />} />
    <Route path="/users" element={<UserList />} />
    <Route path="/user/:userId" element={<User />} />
    <Route path="/newUser" element={<NewUser />} />
    <Route path="/productList" element={<ProductList />} />
    <Route path="/product/:productId" element={<Product />} />
    <Route path="/newProduct" element={<NewProduct />} />
  </Route>
</Routes>
  • Related