如何让React侧边导航组件不受React Router影响,避免不必要重渲染
要实现SideNavigation始终可见且路由切换时不重渲染,核心思路是把SideNavigation从路由组件内部抽离出来,放在路由切换容器(Switch)的外部,让它成为路由结构的兄弟元素,这样路由切换只会影响Switch内的内容组件,而不会触发SideNavigation的重渲染。
具体修改步骤:
调整顶级路由结构
将SideNavigation移到<Switch>外面,作为<BrowserRouter>的直接子元素,和<Switch>同级。这样SideNavigation只会在应用初始化时渲染一次,后续路由切换不会影响它。修改后的顶级渲染代码:
render(( <BrowserRouter onUpdate={() => window.scrollTo(0, 0)}> <div className="app-layout"> {/* SideNavigation 现在处于路由切换范围之外 */} <SideNavigation store={store}/> <Switch> <Route path="/Home" component={MainView} ignoreScrollBehavior/> <Route path="/Graphs" component={NotMainView} ignoreScrollBehavior/> <Route path="/" component={MainView} ignoreScrollBehavior/> </Switch> </div> </BrowserRouter> ), document.getElementById('container') );移除子组件内的SideNavigation
分别修改MainView和NotMainView,去掉它们内部的<SideNavigation>引用,只保留各自的内容部分:MainView的render方法:
render () { return ( <div> <DemoComponent store={store}/> </div> ); }NotMainView的render方法:
render () { return ( <div> <h1>Graph router working</h1> </div> ); }
原理说明:
原来的写法中,每次路由切换时,MainView或NotMainView会被重新挂载/更新,它们内部的SideNavigation也会跟着重新渲染。现在把SideNavigation放在<Switch>外面,它脱离了路由切换的生命周期,只有当顶级的BrowserRouter发生更新(极少发生)时才会重新渲染,完美实现了“菜单始终可见、路由切换仅更新内容区”的需求。
额外优化:如果需要SideNavigation感知当前路由(比如高亮菜单项)
如果你的SideNavigation需要根据当前路由高亮对应的菜单项,可以通过React Router提供的API获取当前路由信息,而不需要让组件整体重渲染:
对于React Router v6+,使用
useLocation钩子:import { useLocation } from 'react-router-dom'; function SideNavigation({ store }) { const location = useLocation(); // 根据location.pathname判断当前激活的菜单项 return ( <nav> <a href="/Home" className={location.pathname === '/Home' ? 'active' : ''} > Home </a> <a href="/Graphs" className={location.pathname === '/Graphs' ? 'active' : ''} > Graphs </a> </nav> ); }对于React Router v5及以下,使用
withRouter高阶组件包裹SideNavigation,注入location属性:import { withRouter } from 'react-router-dom'; function SideNavigation({ store, location }) { // 同样根据location.pathname处理高亮逻辑 return ( // 导航菜单 ); } export default withRouter(SideNavigation);
这种方式下,SideNavigation只会在路由变化时更新必要的高亮状态,而不会整体重渲染,性能更优。
内容的提问来源于stack exchange,提问作者Adam Lagevik

