React Router v6 升级问题:同一路径下如何在div内外渲染多个组件
I see exactly where you're hitting snags with the v6 upgrade—React Router v6 completely changed how nested routing and layout composition works compared to v5. Let's break down the problem and fix it step by step.
The Core Issue in Your Current v6 Code
In v6, <Route> components can only be direct children of <Routes> or other <Route> components—they won't work if nested inside a <div> or regular React component. Also, your approach to rendering multiple components at the same path was missing the proper layout structure that keeps your CSS working as expected.
The Right Approach: Nested Routes with <Outlet>
React Router v6 uses layout routes and the <Outlet> component to handle shared UI (like your Topbar and Sidebar) across multiple routes. Here's how to adapt your code to match your original v5 behavior perfectly:
Step 1: Create an Admin Layout Component
First, make a dedicated layout component that renders your shared UI and uses <Outlet> to inject the page-specific content:
import { Outlet } from 'react-router-dom'; import Topbar from "./components/topbar/Topbar"; import Sidebar from "./components/sidebar/Sidebar"; const AdminLayout = () => { return ( <> <Topbar /> <div className="container"> <Sidebar /> {/* Outlet will render the current matched child route's element */} <Outlet /> </div> </> ); };
Step 2: Update Your App.js Routing
Now use this layout in your routes. All admin-protected routes will be nested under the layout route, so they inherit the Topbar and Sidebar automatically:
import { BrowserRouter as Router, Routes, Route, Outlet } from "react-router-dom"; import Home from "./pages/home/Home"; 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"; import Topbar from "./components/topbar/Topbar"; import Sidebar from "./components/sidebar/Sidebar"; // Define the admin layout here (or move to a separate file for organization) const AdminLayout = () => { return ( <> <Topbar /> <div className="container"> <Sidebar /> <Outlet /> </div> </> ); }; function App() { const admin = JSON.parse(JSON.parse(localStorage.getItem("persist:root"))?.user || "{}")?.currentUser?.isAdmin ; return ( <Router> <Routes> {/* Public login route */} <Route path="/login" element={<Login />} /> {/* Admin-protected routes with shared layout */} {admin && ( <Route path="/" element={<AdminLayout />}> {/* Default route (matches exactly "/") */} <Route index element={<Home />} /> {/* User management routes */} <Route path="/users" element={<UserList />} /> <Route path="/user/:userId" element={<User />} /> <Route path="/newUser" element={<NewUser />} /> {/* Product management routes (fixed path to match v5's "/products" instead of "/productList") */} <Route path="/products" element={<ProductList />} /> <Route path="/product/:productId" element={<Product />} /> <Route path="/newProduct" element={<NewProduct />} /> </Route> )} </Routes> </Router> ); } export default App;
Why This Works
- Layout Reusability: The
AdminLayoutcomponent handles rendering the Topbar and Sidebar once, and<Outlet>takes care of inserting the active page component. This keeps your code DRY and matches your v5 structure exactly. - CSS Compatibility: Your
.containerclass'sdisplay: flexwill work correctly because the Sidebar and Outlet (which holds the page content) are direct children of the container div—just like in your v5 code. - Valid Routing Structure: All
<Route>components are either direct children of<Routes>or nested under another<Route>, which is a requirement for React Router v6 to recognize and process them.
Quick Notes
- I fixed the product list path from
/productListback to/productsto match your v5 code—adjust this if you intentionally changed the path structure. - If you want to handle unauthorized access to admin routes (when
adminis false), you can add a redirect to the login page or an error route, but that's an optional extra for your current issue.
内容的提问来源于stack exchange,提问作者chiheb loussif




