我希望通过自定义属性来增强react-router-dom的路由。每条路线都应包含一个“名称”属性,该属性将作为显示在页面顶部的描述。
理想情况下,我希望 Route 组件显式请求并接受这些自定义属性。这将使我能够在负责用户身份验证和页面布局组装的中间件中访问它们。
下面提供的示例未按预期运行,我目前不确定原因。我遇到的错误是:“未捕获错误:[T]不是组件。其所有组件子级都必须是a或
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>
</>
}
}
据我所知,您无法扩展
Route
组件,但仍然能够在 Routes
或 Route
组件中渲染它,因为它将不再是 Route
的实例,并且无法通过不变检查。
Route
组件已经可以以路由handle属性的形式处理在路由中传递的“额外”数据。这仅适用于较新的数据 API(请参阅选择路由器)。使用路由 handle
传递 name
属性,并使用 useMatches
组件中的
Middleware
钩子来计算匹配并提取 name
。
示例:
const Middleware = () => {
const matches = useMatches();
const name = matches.filter((match) => match.handle?.name).pop()?.handle.name;
return (
<>
<main>
<h1>{name}</h1>
<Outlet />
</main>
</>
);
};
const router = createBrowserRouter([
{
path: "/",
element: <Middleware />,
children: [
...,
{
path: "/test",
element: <>test</>,
handle: {
name: "This is a page"
}
},
...
]
}
]);
如果您不想更新/迁移到 DATA API,那么您可以利用
Middleware
组件的 Outlet
上下文和包装器组件来设置路由名称。
示例:
const Middleware = () => {
const [name, setName] = useState();
return (
<>
<main>
<h1>{name}</h1>
<Outlet context={{ setName }} />
</main>
</>
);
};
const Wrapper = ({ children, name }) => {
const { setName } = useOutletContext();
useEffect(() => {
setName(name);
}, [name]);
return children;
};
const router = createBrowserRouter([
{
path: "/",
element: <Middleware />,
children: [
...,
{
path: "test",
element: (
<Wrapper name="This is a page">
test
</Wrapper>
)
},
...
]
}
]);