React侧边栏点击链接组件不渲染问题(React Router v6)
React Router v6 侧边栏组件无法渲染问题解决
开发带侧边栏的React管理面板时,点击侧边栏链接后对应组件无法正常显示。此前参考的是React Router v5方案,当前使用v6版本,相关代码如下:
原代码
App.jsx
function App() { return ( <> <BrowserRouter> <Header /> <Routes> <Route path="/" index element={<Home />} /> <Route path="/login" element={<Login />} /> <Route path="/adminPanel" element={<AdminPanel />} /> <Route path="/dashboard" element={<Dashboard />} /> <Route path="/scanNow" element={<ScanNow />} /> <Route path="/scanHistory" element={<ScanHistory />} /> <Route path="/users" element={<Users />} /> <Route path="/profile" element={<Profile />} /> <Route path="/settings" element={<Settings />} /> </Routes> </BrowserRouter> </> ) } export default App
AdminPanel.jsx
export default function AdminPanel() { const [selectedComponent, setSelectedComponent] = useState(""); const location = useLocation(); // const isLoggedIn = location.pathname.includes('adminPanel'); return ( <> <div className="adminPanel"> <div className="adminPanel__container"> <SideBar /> <div> {selectedComponent === 'dashboard' && <Dashboard />} {selectedComponent === 'scanNow' && <ScanNow />} {selectedComponent === 'scanHistory' && <ScanHistory />} {selectedComponent === 'users' && <Users />} {selectedComponent === 'profile' && <Profile />} {selectedComponent === 'settings' && <Settings />} </div> </div> </div> </> ) }
SideBar.jsx
export default function SideBar() { const [showMobSidebar, setShowMobSidebar] = useState(false); const [activeLink, setActiveLink] = useState(""); // useEffect to show the mobile sidebar when the component mounts and event // listener is added and removed useEffect(() => { setShowMobSidebar(window.innerWidth < 767); const handleResize = () => { setShowMobSidebar(window.innerWidth < 767); }; window.addEventListener("resize", handleResize); return () => { window.removeEventListener("resize", handleResize); }; }, []); // handle the click for the active link const handleLinkClick = (link) => { setActiveLink(link); }; return ( <> {showMobSidebar ? ( <MobileSidebar /> ) : ( <div className="sidebar"> <ul className="sidebar__lists"> <li className="sidebar__lists-item"> <Link className={`sidebar__lists-link ${activeLink === "dashboard" ? "active" : ""}`} to="/dashboard" onClick={() => handleLinkClick("dashboard")} > <MdDashboard className="react-icons" /> Dashboard </Link> </li> <li className="sidebar__lists-item"> <Link className={`sidebar__lists-link ${activeLink === "scanNow" ? "active" : ""}`} to="/scanNow" onClick={() => handleLinkClick("scanNow")} > <CgPhotoscan className="react-icons" /> Scan Now </Link> </li> <li className="sidebar__lists-item"> <Link className={`sidebar__lists-link ${activeLink === "scanHistory" ? "active" : ""}`} to="/scanHistory" onClick={() => handleLinkClick("scanHistory")} > <MdHistory className="react-icons" /> Scan History </Link> </li> <li className="sidebar__lists-item"> <Link className={`sidebar__lists-link ${activeLink === "users" ? "active" : ""}`} to="/users" onClick={() => handleLinkClick("users")} > <HiOutlineUsers className="react-icons" /> Users </Link> </li> <li className="sidebar__lists-item"> <Link className={`sidebar__lists-link ${activeLink === "profile" ? "active" : ""}`} to="/profile" onClick={() => handleLinkClick("profile")} > <CgProfile className="react-icons" /> Profile </Link> </li> <li className="sidebar__lists-item"> <Link className={`sidebar__lists-link ${activeLink === "settings" ? "active" : ""}`} to="/settings" onClick={() => handleLinkClick("settings")} > <MdOutlineSettings className="react-icons" /> Settings </Link> </li> <li className="sidebar__lists-item"> <Link className={`sidebar__lists-link ${activeLink === "logout" ? "active" : ""}`} to="/login" onClick={() => handleLinkClick("logout")} > <MdOutlineLogout className="react-icons" /> Logout </Link> </li> </ul> </div> )} </> ); }
问题分析
- 路由结构冲突:
/dashboard、/scanNow等是顶级路由,和/adminPanel平级。点击侧边栏的Link会跳转到这些顶级路由,导致AdminPanel组件被卸载,其内部通过selectedComponent控制的组件无法渲染。 - 状态不同步:
AdminPanel的selectedComponent状态从未被更新,侧边栏的handleLinkClick仅维护自身的activeLink,未同步到父组件。
解决方案:使用React Router v6嵌套路由
通过嵌套路由让AdminPanel作为父路由,子路由组件在其内部渲染,同时利用路由自动同步激活状态。
修改后的代码
1. App.jsx(配置嵌套路由)
function App() { return ( <> <BrowserRouter> <Header /> <Routes> <Route path="/" index element={<Home />} /> <Route path="/login" element={<Login />} /> {/* 将AdminPanel设为父路由,嵌套子路由 */} <Route path="/adminPanel" element={<AdminPanel />}> <Route index element={<Dashboard />} /> {/* 默认显示Dashboard */} <Route path="dashboard" element={<Dashboard />} /> <Route path="scanNow" element={<ScanNow />} /> <Route path="scanHistory" element={<ScanHistory />} /> <Route path="users" element={<Users />} /> <Route path="profile" element={<Profile />} /> <Route path="settings" element={<Settings />} /> </Route> </Routes> </BrowserRouter> </> ) } export default App
2. AdminPanel.jsx(添加Outlet渲染子路由)
import { Outlet } from 'react-router-dom'; export default function AdminPanel() { return ( <> <div className="adminPanel"> <div className="adminPanel__container"> <SideBar /> {/* 子路由组件会渲染在此处 */} <Outlet /> </div> </div> </> ) }
3. SideBar.jsx(更新路径并自动同步激活状态)
import { Link, useLocation } from 'react-router-dom'; export default function SideBar() { const [showMobSidebar, setShowMobSidebar] = useState(false); const location = useLocation(); useEffect(() => { setShowMobSidebar(window.innerWidth < 767); const handleResize = () => { setShowMobSidebar(window.innerWidth < 767); }; window.addEventListener("resize", handleResize); return () => { window.removeEventListener("resize", handleResize); }; }, []); // 根据当前路径判断链接是否激活 const isActive = (path) => { return location.pathname.includes(path); }; return ( <> {showMobSidebar ? ( <MobileSidebar /> ) : ( <div className="sidebar"> <ul className="sidebar__lists"> <li className="sidebar__lists-item"> <Link className={`sidebar__lists-link ${isActive("dashboard") ? "active" : ""}`} to="/adminPanel/dashboard" > <MdDashboard className="react-icons" /> Dashboard </Link> </li> <li className="sidebar__lists-item"> <Link className={`sidebar__lists-link ${isActive("scanNow") ? "active" : ""}`} to="/adminPanel/scanNow" > <CgPhotoscan className="react-icons" /> Scan Now </Link> </li> <li className="sidebar__lists-item"> <Link className={`sidebar__lists-link ${isActive("scanHistory") ? "active" : ""}`} to="/adminPanel/scanHistory" > <MdHistory className="react-icons" /> Scan History </Link> </li> <li className="sidebar__lists-item"> <Link className={`sidebar__lists-link ${isActive("users") ? "active" : ""}`} to="/adminPanel/users" > <HiOutlineUsers className="react-icons" /> Users </Link> </li> <li className="sidebar__lists-item"> <Link className={`sidebar__lists-link ${isActive("profile") ? "active" : ""}`} to="/adminPanel/profile" > <CgProfile className="react-icons" /> Profile </Link> </li> <li className="sidebar__lists-item"> <Link className={`sidebar__lists-link ${isActive("settings") ? "active" : ""}`} to="/adminPanel/settings" > <MdOutlineSettings className="react-icons" /> Settings </Link> </li> <li className="sidebar__lists-item"> <Link className={`sidebar__lists-link ${isActive("login") ? "active" : ""}`} to="/login" > <MdOutlineLogout className="react-icons" /> Logout </Link> </li> </ul> </div> )} </> ); }
关键修改点
- 嵌套路由配置:将Dashboard等组件设为
/adminPanel的子路由,确保点击链接时AdminPanel保持挂载。 - Outlet组件:替代原有的条件渲染逻辑,专门用于渲染子路由组件。
- 自动激活状态:通过
useLocation获取当前路径,自动判断链接是否激活,无需手动维护状态。 - 路径更新:侧边栏链接路径改为
/adminPanel/xxx,匹配嵌套路由结构。
内容的提问来源于stack exchange,提问作者user19662721
相关产品推荐
相关产品推荐

