如何扩展react-router-dom的Route组件以支持自定义props?
为react-router-dom的Route组件添加自定义name属性的解决方案
问题背景
我想给react-router-dom的Route组件添加自定义name属性,用来在页面顶部展示页面描述,同时希望这些自定义属性能被显式声明,方便在用户认证、页面布局的中间件中访问。但自己写的代码无法运行,报错:
Uncaught Error: [T] is not a
component. All component children of must be a or <React.Fragment>
我之前的代码如下:
自定义Route组件代码
import { RouteProps, Route as R } from "react-router-dom" type Props = RouteProps & { name?: string } export const T: React.FC<Props> = ({...props}) => { return <R {...props} /> }
路由配置代码
import { BrowserRouter, Routes } from "react-router-dom"; import { T } from "@components/Route" const RoutesApp = () => { return ( <BrowserRouter> <Routes> <T path="/" element={<Middleware />} > <T path="test" name="This is a page" element={<>test</>} /> </T> </Routes> </BrowserRouter> ); }; export default RoutesApp;
中间件组件代码
import { Outlet } from "react-router-dom"; export const Middleware = () => { if(...) return <> <main> <h1>{name}</h1> <Outlet /> </main> </> } }
错误原因
react-router-dom v6对<Routes>的子组件有严格要求:必须是官方提供的<Route>组件或<React.Fragment>,自定义的包装组件(比如你写的T)不会被识别,因此抛出错误。同时v6的嵌套路由写法也和v5不同,不能直接用组件嵌套的方式定义子路由。
解决步骤
1. 扩展RouteProps类型(TS可选,JS可跳过)
先扩展官方的RouteProps类型,添加我们需要的name属性,确保类型检查通过:
import { RouteProps } from "react-router-dom"; export type CustomRouteProps = RouteProps & { name?: string; };
2. 直接使用官方Route配置路由
不需要自定义包装组件,直接给官方<Route>添加name属性,同时按照v6的规则配置嵌套路由:
import { BrowserRouter, Routes, Route } from "react-router-dom"; import { Middleware } from "./Middleware"; const RoutesApp = () => { return ( <BrowserRouter> <Routes> {/* 父路由:element渲染中间件,children定义子路由 */} <Route path="/" element={<Middleware />}> {/* 直接给官方Route添加自定义name属性 */} <Route path="test" name="This is a page" element={<>test</>} /> </Route> </Routes> </BrowserRouter> ); }; export default RoutesApp;
3. 在中间件中获取自定义name属性
使用useMatches钩子获取当前匹配的路由信息,从中提取name属性:
import { Outlet, useMatches } from "react-router-dom"; export const Middleware = () => { // 获取所有匹配的路由数组,最后一项是当前页面的路由 const matches = useMatches(); const currentRoute = matches[matches.length - 1]; const pageName = currentRoute?.name || "默认页面"; // 这里可以添加你的用户认证逻辑 return ( <main> <h1>{pageName}</h1> <Outlet /> </main> ); };
关键说明
- v6的
<Routes>只认官方<Route>,别再自定义包装组件当路由用 - 嵌套路由通过父
<Route>的children属性定义,父路由的element里用<Outlet>渲染子路由内容 useMatches能拿到所有匹配的路由元数据,包括我们自定义的name属性,适合在布局、中间件中统一处理页面信息
内容的提问来源于stack exchange,提问作者Luiz
相关产品推荐
相关产品推荐

