React嵌套路由传递props问题:this.props.match为undefined
match.params的问题 看起来你遇到的核心问题是:路由参数虽然出现在地址栏里,但嵌套在Dashboard/Layout里的子组件(比如UpdateProperty、SingleProperty)无法拿到this.props.match,原因很简单——你在Route的render回调里没有把路由相关的props传递给子组件。
问题根源
当你使用render={() => <Dashboard><UpdateProperty /></Dashboard>}这种写法时,React Router会把match、location、history这些路由专属props传递给render回调函数,但你没有把这些props传递给Dashboard或者它内部的UpdateProperty组件,导致子组件里的this.props.match是undefined。
解决方案1:直接在render里传递props
最简单的方式是在render回调里接收路由props,然后把它传递给需要的子组件:
// 修改你的路由配置 <Route exact path="/admin/dashboard/update/:slug" render={(routeProps) => ( <Dashboard> {/* 把路由props传递给UpdateProperty */} <UpdateProperty {...routeProps} /> </Dashboard> )} /> <Route exact path="/property/:slug" render={(routeProps) => ( <Layout> <SingleProperty {...routeProps} /> </Layout> )} />
这样修改后,UpdateProperty和SingleProperty组件里就能通过this.props.match.params.slug拿到参数了。
解决方案2:让布局组件自动传递路由props(更优雅)
如果你的布局组件(Dashboard/Layout)会被多个路由使用,每次都手动传递props会很麻烦。可以修改布局组件,让它自动把接收到的路由props传递给子元素:
修改Dashboard组件:
import React from 'react'; import DashboardNav from '../components/DashboardNav' const Dashboard = ({ children, ...routeProps }) => { // 克隆子元素并注入路由props const childWithRouteProps = React.cloneElement(children, routeProps); return ( <section className=""> <div className="row"> <div id="main" className="col-sm-12 d-flex"> {/* 原有侧边栏代码不变 */} <aside id="sidebar" className="dashboard col-md-2 bg-secondary"> <ul className="nav flex-column justify-content-center align-items-center"> <li className="nav-item py-md-4 px-md-3"> <Link className="nav-link active text-white" to="#">Logo</Link> </li> <li className="nav-item p-md-3"> <Link className="nav-link active text-white" to="#">Dashboard</Link> </li> <li className="nav-item p-md-3"> <Link className="nav-link text-white" to="#">All Properties</Link> </li> <li className="nav-item p-md-3"> <Link className="nav-link text-white" to="#">New Properties</Link> </li> <li className="nav-item p-md-3"> <Link className="nav-link text-white" to="#">Messages</Link> </li> <li className="nav-item p-md-3"> <Link className="nav-link text-white" to="#">About</Link> </li> <li className="nav-item p-md-3"> <Link className="nav-link text-white" to="#">Contact</Link> </li> <li className="nav-item p-md-3"> <Link className="nav-link text-white" to="#">Blog</Link> </li> <li className="nav-item p-md-3"> <Link className="nav-link text-white" to="#">Logout</Link> </li> </ul> </aside> <article id="dashboard" className="col-sm-12 col-md-10"> <header id="menu" className="dashboard d-flex flex-column"> <DashboardNav /> </header> <main className="py-md-3"> {/* 渲染注入了props的子组件 */} { childWithRouteProps } </main> </article> </div> </div> </section> ) }
修改Layout组件:
import React from 'react'; import Navbar from './Navbar' const Layout = ({ children, ...routeProps }) => { const childWithRouteProps = React.cloneElement(children, routeProps); return ( <> <Navbar /> { childWithRouteProps } </> ); } export default Layout;
然后路由配置可以简化为:
<Route exact path="/admin/dashboard/update/:slug" render={(routeProps) => ( <Dashboard {...routeProps}> <UpdateProperty /> </Dashboard> )} /> <Route exact path="/property/:slug" render={(routeProps) => ( <Layout {...routeProps}> <SingleProperty /> </Layout> )} />
解决方案3:使用withRouter高阶组件
如果某个组件需要访问路由props,但它不是直接被Route渲染的(比如嵌套了多层),可以用react-router-dom提供的withRouter高阶组件包裹它:
// 在UpdateProperty组件中引入withRouter import { withRouter } from 'react-router-dom'; class UpdateProperty extends React.Component { componentDidMount() { // 现在可以正常获取slug了 const { slug } = this.props.match.params; console.log(slug); } render() { // ...组件内容 } } // 用withRouter包裹组件,注入路由props export default withRouter(UpdateProperty);
这种方式适合那些需要在深层嵌套组件中访问路由信息的场景,不需要修改上层的布局组件或路由配置。
内容的提问来源于stack exchange,提问作者Lawrence Eagles

