React Router中Route的component属性与children写法有什么差异?
React Router 两种Route写法的差异解答
核心差异触发前提
你没有观察到差异,是因为你的示例中App组件没有状态更新逻辑,不会触发重渲染,两种写法的差异只有在父组件(App)发生重渲染、且当前路由未切换时才会显现。
两种写法的底层逻辑区别
1. path='/uno'的component传内联函数写法
你写的<Route path='/uno' component={(props) => <PropComp {...props}/>}/>存在一个问题:component属性接收的是每次App渲染都会重新生成的匿名函数,React Router v5的component属性逻辑是:
- 只要传入的组件引用发生变化,就会直接卸载旧的组件实例,创建并挂载新的实例
- 这会直接导致
PropComp的空依赖useEffect每次App重渲染都触发,同时组件内的counter状态会被清空重置
如果你改成component={PropComp}直接传组件引用,就不会有这个问题,和children写法的挂载表现一致。
2. path='/dos'的children写法
直接把<PropComp/>写在Route标签内部的写法,组件的实例引用是稳定的,即使App重渲染,只要路由没有切换,PropComp就不会被卸载重挂载,状态会保留,空依赖的useEffect也只会在第一次路由匹配时触发一次。
验证测试方法
你可以给App组件添加状态更新逻辑,就能直观看到差异:
// 修改后的App.js import { BrowserRouter as Router, Link, Route } from 'react-router-dom'; import { PropComp } from './PropComp'; import { useState } from 'react'; function App() { // 新增App自身的状态 const [appCount, setAppCount] = useState(0) return ( <div className="App"> {/* 新增触发App重渲染的按钮 */} <button onClick={() => setAppCount(prev => prev + 1)}>触发App更新 当前计数:{appCount}</button> <Router> <Link to='/uno'>uno</Link> <p>...</p> <Link to='/dos'>dos</Link> <Route path='/uno' component={(props) => <PropComp {...props}/>}/> <Route path='/dos'> <PropComp/> </Route> </Router> </div> ); } export default App;
测试步骤:
- 切换到
/uno路由,点击Sum按钮把counter调到5,点击上方的触发App更新按钮,会看到counter清零,控制台多打印一次PropComp mounted - 切换到
/dos路由,同样把counter调到5,点击触发App更新按钮,counter不会变化,控制台也不会新增挂载日志
为什么修改动画示例没有看到变化?
动画过渡示例的场景是路由切换时的动画,路由切换本身就会触发组件的卸载和挂载,两种写法在路由切换时的表现一致,所以你看不到差异。
内容的提问来源于stack exchange,提问作者Fabio Gomez
相关产品推荐
相关产品推荐

