Как я могу расширить компонент маршрута, включив в него пользовательские реквизиты?

Я хочу дополнить маршрут реагирования-маршрутизатора-dom настраиваемыми свойствами. Каждый маршрут должен включать атрибут «имя», который будет служить описанием, отображаемым вверху страницы.

В идеале я бы хотел, чтобы компонент Route явно запрашивал и принимал эти пользовательские свойства. Это позволило бы мне получить к ним доступ в промежуточном программном обеспечении, отвечающем за аутентификацию пользователя и сборку макета страницы.

Приведенный ниже пример не работает должным образом, и в настоящее время я не уверен в причине. Ошибка, с которой я столкнулся: «Неперехваченная ошибка: [T] не является компонентом. Все дочерние компоненты должны быть a или <React.Fragment>».

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>
    </>
  }
}
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
2
0
98
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

AFAIK, вы не можете расширить компонент Route и при этом иметь возможность отображать его внутри компонентов Routes или Route, поскольку он больше не будет экземпляром Route и не пройдет проверку инварианта.

API данных

Компонент Route уже может обрабатывать «лишние» данные, передаваемые в маршруте, в виде дескриптора маршрута prop. Это работает только в новых 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, не связанные с данными

Если вы не хотите обновлять/переходить на API-интерфейсы DATA, вы можете использовать контекст Middleware компонента Outlet и компонент-оболочку для установки имени маршрута. Используйте локальное состояние React для хранения значения name и предоставления обратного вызова установщика в контексте Outlet. Компонент-обертка принимает свойство name и обновляет состояние Middleware текущим именем. Каждый маршрутизируемый компонент заворачивается в обертку для задания имени.

Пример:

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>
        )
      },
      ...,
      
      {
        path: "test",
        element: (
          <Wrapper> // <-- "unset" name
            test 2
          </Wrapper>
        )
      },
      ...
    ]
  }
]);

Другие вопросы по теме