caseyjhol
¿Es posible obtener el patrón de ruta para la ruta actualmente coincidente? Ejemplo:
<Route
path=":state/:city*"
element={
<Page />
}
/>
// Page.jsx
function Page() {
...
// usePathPattern doesn't actually exist
const pathPattern = usePathPattern(); // pathPattern = ":state/:city*"
...
}
Sé que puedo usar useMatch
para verificar si la ubicación actual coincide con un patrón de ruta específico, pero luego el componente debe saber cuál es el patrón de ruta.
Futián Shen
Hice un gancho personalizado useCurrentPath
con react-router v6 para obtener la ruta actual de la ruta, y me funciona
Si el nombre de ruta actual es /members/5566
conseguiré el camino /members/:id
import { matchRoutes, useLocation } from "react-router-dom"
const routes = [{ path: "/members/:id" }]
const useCurrentPath = () => {
const location = useLocation()
const [{ route }] = matchRoutes(routes, location)
return route.path
}
function MemberPage() {
const currentPath = useCurrentPath() // `/members/5566` -> `/members/:id`
return <></>
}
Referencia
-
Esto funciono muy bien para mi. El gancho personalizado es una preferencia personal. Sin embargo,
useLocation
+matchRoutes
es la respuesta.– Herman J. Radtke III
1 de mayo a las 19:33
-
Esto no parece funcionar con rutas anidadas con rutas relativas. por ejemplo, cuando
location.pathname
es"/users/123/profile"
peroroutes[0].path
es"profile"
debido a que está anidado debajo"users/:id"
. ¿Tienes una solución para eso?– eliw00d
28 de julio a las 20:56
m.wrona
No estoy seguro de si resuelve completamente su caso de uso, pero en mi caso usé una combinación de useLocation
y useParams
. Aquí está el código:
import React from 'react';
import { useLocation, useParams } from 'react-router-dom';
import type { Location, Params } from 'react-router-dom';
/**
* Function converts path like /user/123 to /user/:id
*/
const getRoutePath = (location: Location, params: Params): string => {
const { pathname } = location;
if (!Object.keys(params).length) {
return pathname; // we don't need to replace anything
}
let path = pathname;
Object.entries(params).forEach(([paramName, paramValue]) => {
if (paramValue) {
path = path.replace(paramValue, `:${paramName}`);
}
});
return path;
};
export const Foo = (): JSX.Element => {
const location = useLocation();
const params = useParams();
const path = getRoutePath(location, params);
(...)
};
-
Esta solución se rompería cuando las partes de la ruta tengan el mismo valor, por ejemplo
/user/1/badge/1/comment/1
. Si bien ese es un escenario poco común, esta solución aún no es universalmente confiable.– Ben Barkay
30 abr a las 12:47
-
mejor usar reactrouter.com/docs/en/v6/api#matchroutes en cambio.
– Herman J. Radtke III
1 de mayo a las 19:32
-
El enlace de @HermanJ.RadtkeIII parece estar roto. tal vez te refieres este
– Reimirno
7 de julio a las 3:51
Desde dentro del contexto de un Route
puedes conseguir el path
a través de varios métodos establecidos en los documentos.
Mi problema era ligeramente diferente en el sentido de que necesitaba el path
fuera del contexto de la Route
y llegó a la siguiente solución que también debería funcionar para usted:
import {
matchPath,
useLocation
} from "react-router-dom";
const routes = [ ':state/:city', ...otherRoutes ];
function usePathPattern() {
const { pathname } = useLocation();
return matchPath( pathname, routes )?.path;
}
-
Su enlace de documentación apunta a los documentos v5, no a los documentos v6, y por lo tanto no es útil.
– Chris Kitching
16 de enero a las 4:25
-
RicoN
Esto parece funcionar con lo que realmente exportan a partir de 6.2.1, sin embargo, utiliza un componente que exportan como UNSAFE_
import { UNSAFE_RouteContext } from 'react-router-dom';
const reconstructPath = (matches) =>
matches
.map(({ route: { path } }) =>
path.endsWith('/*') ? path.slice(0, -1) : path ? path + "https://stackoverflow.com/" : ''
)
.join('');
const findLastNode = (node) =>
node.outlet ? findLastNode(node.outlet.props.value) : node;
const usePathPattern = () =>
reconstructPath(
findLastNode(React.useContext(UNSAFE_RouteContext)).matches
);
esto me funciona facilmente
en primer lugar, importe la ubicación de uso desde react-router-dom
import { useLocation } from "react-router-dom"
después
const location = useLocation();
console.log(location.pathname);
-
Esto da la ruta literal, no el patrón de ruta.
– Antonio O.
10 ene a las 19:39
Tobi
Escribí un enlace personalizado para ese propósito, ya que no parece ser compatible con oob en este momento:
Nota: aún no se ha probado a fondo. Así que úsalo con precaución.
import { useLocation, useParams } from 'react-router';
export function useRoutePathPattern() {
const routeParams = useParams();
const location = useLocation();
let routePathPattern = location.pathname;
Object.keys(routeParams)
.filter((paramKey) => paramKey !== '*')
.forEach((paramKey) => {
const paramValue = routeParams[paramKey];
const regexMiddle = new RegExp(`\/${paramValue}\/`, 'g');
const regexEnd = new RegExp(`\/${paramValue}$`, 'g');
routePathPattern = routePathPattern.replaceAll(
regexMiddle,
`/:${paramKey}/`,
);
routePathPattern = routePathPattern.replaceAll(regexEnd, `/:${paramKey}`);
});
return routePathPattern;
}
-
Esto da la ruta literal, no el patrón de ruta.
– Antonio O.
10 ene a las 19:39
labitiotis
Para encontrar la ruta coincidente en react-router v6, debe usar el matchPath
función. Deberá almacenar todas sus rutas en una variable como una matriz. Luego puede recorrer todas las rutas y usar esa función para encontrar la ruta coincidente. Con cuidado, ya que coincidirá con el primer valor real, idealmente debe recorrerlos en el mismo orden en que los ha representado.
Esta no es una solución perfecta, ya que es posible que no maneje rutas anidadas a menos que las almacene en la misma variable.
Aquí hay un ejemplo:
rutas.ts
const routes = [
{ name: 'Home', path: '/home', element: Home },
{ name: 'Profile', path: '/profile', element: Profile },
{ name: '404', path: '*', element: NotFound },
];
Aplicación.tsx
<App>
<BrowserRouter>
<Header />
<Routes>
{routes.map((route, key) => (
<Route key={key} path={route.path} element={<route.element />} />
))}
</Routes>
</BrowserRouter>
</App
usarMatchedRoute.tsx
import { matchPath } from 'react-router';
export function useMatchedRoute() {
const { pathname } = useLocation();
for (const route of routes) {
if (matchPath({ path: route.path }, pathname)) {
return route;
}
}
}
Encabezado.tsx
export function Header() {
const route = useMatchedRoute();
return <div>{route.name}</div>
}