如何扩展路线组件以合并自定义道具?

问题描述 投票:0回答:1

我希望通过自定义属性来增强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>
    </>
  }
}
reactjs react-router-dom
1个回答
0
投票

据我所知,您无法扩展

Route
组件,但仍然能够在
Routes
Route
组件中渲染它,因为它将不再是
Route
的实例,并且无法通过不变检查。

数据API

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"
        }
      },
      ...
    ]
  }
]);

非数据 API

如果您不想更新/迁移到 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>
        )
      },
      ...
    ]
  }
]);
© www.soinside.com 2019 - 2024. All rights reserved.