React Router Dom:如何根据当前路径控制组件的显示与隐藏?
解决方案
要实现根据路径显示/隐藏Navbar、Newsletter、Footer这类全局组件,核心是让组件能访问到路由上下文(useLocation必须在BrowserRouter内部使用),以下是两种可行方案:
方案一:拆分内部组件(快速改造)
把原App中BrowserRouter内部的内容拆成独立组件,该组件处于路由上下文内,可正常使用useLocation:
import { BrowserRouter, Routes, Route, Navigate, useLocation } from 'react-router-dom'; // 外层App仅负责包裹BrowserRouter function App() { return ( <BrowserRouter> <AppContent /> </BrowserRouter> ); } // 内部组件,可访问路由上下文 function AppContent() { const location = useLocation(); // 定义需要隐藏全局组件的路径 const hiddenPaths = ['/login', '/register', '/account', '/forgot-password']; // 按需判断是否显示对应组件 const showNavbar = !hiddenPaths.includes(location.pathname); const showNewsletter = !hiddenPaths.includes(location.pathname); const showFooter = !hiddenPaths.includes(location.pathname); // 可按需调整 return ( <> <Wrapper> {showNavbar && ( <> <Announcement /> <Navbar /> </> )} <Routes> <Route index path="/" element={<Home />}></Route> <Route path="/products" element={<ProductList />}></Route> <Route path="/products/:category" element={<ProductList category="true" />}></Route> <Route path="/product/:id" element={<Product />}></Route> <Route path="/register" element={isAuthenticated ? <Navigate replace to="/" /> : <Register />}></Route> <Route path="/login" element={isAuthenticated ? <Navigate replace to="/" /> : <Login />}></Route> <Route path="/account" element={isAuthenticated ? <Navigate replace to="/" /> : <Account />}></Route> <Route path="/forgot-password" element={isAuthenticated ? <Navigate replace to="/" /> : <ForgotPassword />}></Route> <Route path="/cart" element={<Cart />}></Route> <Route path="/wishlist" element={<Wishlist />}></Route> <Route path="/orders/tracking" element={<Tracking />}></Route> <Route path="/orders/checkout" element={<Checkout />}></Route> </Routes> {showNewsletter && <Newsletter />} </Wrapper> {showFooter && <Footer />} </> ); } export default App;
方案二:使用Layout布局组件(推荐,符合React Router最佳实践)
通过Outlet创建共享布局,将全局组件封装到Layout中,路由结构更清晰,适合多布局场景:
- 先创建Layout组件:
import { useLocation, Outlet } from 'react-router-dom'; const Layout = () => { const location = useLocation(); const hiddenPaths = ['/login', '/register', '/account', '/forgot-password']; const showNavbar = !hiddenPaths.includes(location.pathname); const showNewsletter = !hiddenPaths.includes(location.pathname); return ( <Wrapper> {showNavbar && ( <> <Announcement /> <Navbar /> </> )} <Outlet /> {/* 渲染当前路由对应的页面内容 */} {showNewsletter && <Newsletter />} </Wrapper> ); };
- 修改App.js的路由结构:
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom'; function App() { return ( <BrowserRouter> <Routes> {/* 所有需要共享Layout的路由作为子路由 */} <Route element={<Layout />}> <Route index path="/" element={<Home />}></Route> <Route path="/products" element={<ProductList />}></Route> <Route path="/products/:category" element={<ProductList category="true" />}></Route> <Route path="/product/:id" element={<Product />}></Route> <Route path="/cart" element={<Cart />}></Route> <Route path="/wishlist" element={<Wishlist />}></Route> <Route path="/orders/tracking" element={<Tracking />}></Route> <Route path="/orders/checkout" element={<Checkout />}></Route> </Route> {/* 不需要Layout的路由单独定义(如登录、注册) */} <Route path="/register" element={isAuthenticated ? <Navigate replace="/" /> : <Register />}></Route> <Route path="/login" element={isAuthenticated ? <Navigate replace="/" /> : <Login />}></Route> <Route path="/account" element={isAuthenticated ? <Navigate replace="/" /> : <Account />}></Route> <Route path="/forgot-password" element={isAuthenticated ? <Navigate replace="/" /> : <ForgotPassword />}></Route> </Routes> {/* Footer如果需要判断路径,也可以放到Layout中,或者单独处理 */} {/* <Footer /> */} </BrowserRouter> ); } export default App;
关键说明
- 之前无法使用
useLocation是因为该钩子必须在BrowserRouter内部的组件中调用,原App组件是渲染BrowserRouter的外层组件,不在路由上下文范围内。 - 两种方案都能解决问题,方案二更适合中大型项目,便于后续扩展不同的布局模板。
内容的提问来源于stack exchange,提问作者felixkpt
相关产品推荐
相关产品推荐

