React:如何在静态NavBar组件内渲染子组件且避免重渲染?
要实现在NavBar内渲染子组件同时避免其不必要重渲染,核心思路是让NavBar只在自身props真正变化时才重新渲染,同时确保传递给它的props(包括children)引用稳定。以下是具体步骤和代码示例:
1. 让NavBar组件具备“按需渲染”能力
首先要确保NavBar不会因为父组件的无关渲染而跟着刷新,我们可以通过React的内置优化工具实现:
如果是函数组件:用React.memo包裹
React.memo会对组件的props进行浅比较,只有当props真正变化时才重新渲染组件:
import React, { memo } from 'react'; import { NavBar as AntNavBar } from 'antd'; const NavBar = memo(({ title, children }) => { // 可以加个日志测试是否重渲染 console.log('NavBar 渲染了'); return ( <AntNavBar title={title}> {children} {/* 这里渲染传入的子组件 */} </AntNavBar> ); }); export default NavBar;
如果是类组件:继承PureComponent
PureComponent会自动在shouldComponentUpdate中浅比较props和state,避免不必要的重渲染:
import React, { PureComponent } from 'react'; import { NavBar as AntNavBar } from 'antd'; class NavBar extends PureComponent { render() { console.log('NavBar 渲染了'); const { title, children } = this.props; return ( <AntNavBar title={title}> {children} </AntNavBar> ); } } export default NavBar;
2. 稳定传递children的引用
父组件(比如你的App组件)在路由切换时会重新渲染,如果直接在render里创建NavBar的子组件,每次都会生成新的JSX引用,导致NavBar的children props变化,触发重渲染。我们需要让children的引用保持稳定:
方案一:静态子组件用useMemo缓存(函数组件App)
如果NavBar的子组件是静态的(比如导航菜单),用useMemo缓存它,确保每次父组件渲染时引用不变:
import { HashRouter, Route } from 'react-router-dom'; import React, { useMemo } from 'react'; import NavBar from './NavBar'; import HomePage from './HomePage'; import MarketPage from './MarketPage'; import { Menu } from 'antd'; function App() { console.log('App 渲染了'); // 用useMemo缓存导航菜单,空依赖数组确保只创建一次 const navChildren = useMemo(() => ( <Menu mode="horizontal"> <Menu.Item key="home">首页</Menu.Item> <Menu.Item key="market">市场</Menu.Item> </Menu> ), []); return ( <HashRouter> <div className="App"> {/* 静态导航区 */} <div> <NavBar title="MyApp">{navChildren}</NavBar> </div> {/* 动态路由区 */} <div> {/* 注意修正路由path:把"//"改成"/"并加上exact,避免匹配所有路由 */} <Route exact path="/" component={HomePage} /> <Route path="/market" component={MarketPage}/> </div> </div> </HashRouter> ); } export default App;
方案二:把静态子组件作为类实例属性(类组件App)
如果你的App是类组件,可以把NavBar的子组件放在类的实例属性中,避免每次render重新创建:
import { HashRouter, Route } from 'react-router-dom'; import React, { Component } from 'react'; import NavBar from './NavBar'; import HomePage from './HomePage'; import MarketPage from './MarketPage'; import { Menu } from 'antd'; class App extends Component { // 把导航菜单作为实例属性,只创建一次 navChildren = ( <Menu mode="horizontal"> <Menu.Item key="home">首页</Menu.Item> <Menu.Item key="market">市场</Menu.Item> </Menu> ); render() { console.log('App 渲染了'); return ( <HashRouter> <div className="App"> <div> <NavBar title="MyApp">{this.navChildren}</NavBar> </div> <div> <Route exact path="/" component={HomePage} /> <Route path="/market" component={MarketPage}/> </div> </div> </HashRouter> ); } } export default App;
3. 验证效果
现在切换路由时,你会看到控制台只打印App 渲染了,而不会打印NavBar 渲染了,说明NavBar没有跟着重渲染,同时它的子组件也能正常显示。
关键总结
- 组件优化:用
React.memo(函数组件)或PureComponent(类组件)让NavBar只在props变化时渲染 - 稳定props:确保传递给NavBar的所有props(包括
children)引用不变,避免父组件渲染时触发不必要的props更新 - 路由修正:原代码中的
path="//"是错误的,改成path="/"并加上exact,避免路由匹配异常
内容的提问来源于stack exchange,提问作者ninesalt
相关产品推荐
相关产品推荐

