如何在React中嵌套React Router实现侧边栏不重复渲染
你要实现的「侧边栏公共布局+内容区动态切换」效果,本质是用嵌套路由把侧边栏作为父层公共组件,子路由仅渲染内容区域,按以下步骤修改即可:
1. 修改App.js路由配置
你原来给根路由加了exact属性,会导致所有/开头的子路由无法匹配到Dashboard父组件,直接移除该属性即可:
import "./App.css"; import LoginForm from "./components/LoginForm"; import { AuthProvider } from "./contexts/AuthContext"; import { BrowserRouter as Router, Switch, Route } from "react-router-dom"; import Dashboard from "./components/Dashboard"; import PrivateRoute from "./components/PrivateRoute"; function App() { return ( <div className="App"> <Router> <AuthProvider> <Switch> {/* 移除exact,允许子路由匹配 */} <PrivateRoute path="/" component={Dashboard} /> <Route path="/login" component={LoginForm} /> </Switch> </AuthProvider> </Router> </div> ); } export default App;
2. 完善Dashboard组件的嵌套路由与布局
在Dashboard内新增flex布局拆分侧边栏和内容区,内容区预留嵌套路由的渲染出口,示例如下(你可以替换成自己的业务子组件):
import React from "react"; import { useAuth } from "../contexts/AuthContext"; import { useHistory, Switch, Route } from "react-router-dom"; import Sidebar from "./Sidebar/Sidebar"; import { useRouteMatch } from "react-router"; // 示例业务子组件,你可以换成自己的页面 import Home from "./Home"; import Settings from "./Settings"; import Profile from "./Profile"; const Dashboard = () => { const { currentUser, logout } = useAuth(); const history = useHistory(); let { path, url } = useRouteMatch(); const handleLogout = async () => { try { await logout(); history.push("/login"); } catch (error) { console.log(error); } }; if (!currentUser) return null; return ( // 新增flex布局,侧边栏和内容区并排 <div style={{ display: 'flex', height: '100vh' }}> <Sidebar logout={handleLogout} url={url} /> {/* 内容区,嵌套路由渲染在这里 */} <div style={{ flex: 1, padding: '20px', overflow: 'auto' }}> <Switch> <Route exact path={path} component={Home} /> <Route path={`${path}/settings`} component={Settings} /> <Route path={`${path}/profile`} component={Profile} /> </Switch> </div> </div> ); }; export default Dashboard;
3. 侧边栏跳转配置
Sidebar组件内用react-router的Link组件做跳转,路径用传入的url拼接即可,示例:
import { Link } from "react-router-dom"; const Sidebar = ({ logout, url }) => { return ( <div style={{ width: '200px', background: '#f5f5f5', padding: '20px' }}> <Link to={url} style={{ display: 'block', margin: '10px 0' }}>首页</Link> <Link to={`${url}/profile`} style={{ display: 'block', margin: '10px 0' }}>个人中心</Link> <Link to={`${url}/settings`} style={{ display: 'block', margin: '10px 0' }}>系统设置</Link> <button onClick={logout} style={{ marginTop: '20px' }}>退出登录</button> </div> ) }
新手开发建议
- 路由路径尽量语义化,后续扩展可以把Dashboard的父路由改成
/dashboard而非直接用根路由,避免和其他路由冲突 - 业务路由较多时可以抽成单独的配置文件,不用分散写在各个组件里,维护更方便
- 侧边栏的激活状态可以用
useLocation拿到当前路径,和跳转路径对比后添加高亮样式 - 子组件需要路由参数、跳转能力时直接用
useParams、useHistory等内置hook即可,不用逐层传props
内容的提问来源于stack exchange,提问作者Citrus
相关产品推荐
相关产品推荐

