programing

react-module v6: 현재 루트의 경로 패턴 가져오기

fastcode 2023. 3. 16. 21:58
반응형

react-module v6: 현재 루트의 경로 패턴 가져오기

현재 일치하는 경로의 경로 패턴을 얻을 수 있습니까?예를 들어:

<Route
    path=":state/:city*"
    element={
        <Page />
    }
/>
// Page.jsx

function Page() {
    ...
    // usePathPattern doesn't actually exist
    const pathPattern = usePathPattern(); // pathPattern = ":state/:city*"
    ...
}

도 쓸 수 거 알아useMatch현재 위치가 특정 경로 패턴과 일치하는지 여부를 확인하려면 구성 요소가 경로 패턴을 알아야 합니다.

을 맞춤 제작했습니다.useCurrentPath또, 이것은, 에게 있어서 기능합니다.

이 「」인 ./members/5566는 '경로'를 잡겠습니다./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 <></>
}

언급

https://reactrouter.com/en/v6.3.0/api#matchroutes

사용 사례를 완전히 해결할 수 있을지는 모르겠지만, 제 경우에는 다음 두 가지를 조합하여 사용했습니다.useLocation ★★★★★★★★★★★★★★★★★」useParams을 사용하다

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);

  (...)
};

Routepath 가지 방법을 통해 정보를 얻을 수 있습니다.

는 조금 , 은 내가 제 the the the the the the the the the the my my my the the the the the the 했다는 것이다.pathRoute고객님께도 도움이 될 수 있는 다음과 같은 솔루션을 제공했습니다.

import {
    matchPath,
    useLocation
} from "react-router-dom";

const routes = [ ':state/:city', ...otherRoutes ];

function usePathPattern() {

    const { pathname } = useLocation();

    return matchPath( pathname, routes )?.path;
}

이것은 나에게 쉽게 통한다.

첫 번째로 반응성 도메인으로부터의 Import 사용 장소

import { useLocation } from "react-router-dom"

그리고나서

const location = useLocation();
console.log(location.pathname);

이것은 6.2.1 시점에서 실제로 내보내는 것과 동작하는 것처럼 보이지만, 안전하지 않게 내보내는 컴포넌트를 사용합니다.

import { UNSAFE_RouteContext } from 'react-router-dom';

const reconstructPath = (matches) =>
  matches
    .map(({ route: { path } }) =>
      path.endsWith('/*') ? path.slice(0, -1) : path ? path + '/' : ''
    )
    .join('');

const findLastNode = (node) =>
  node.outlet ? findLastNode(node.outlet.props.value) : node;

const usePathPattern = () =>
  reconstructPath(
    findLastNode(React.useContext(UNSAFE_RouteContext)).matches
  );

지금은 OOB를 지원하지 않는 것 같아서 이 목적을 위해 커스텀훅을 작성했습니다.

주의: 아직 충분히 테스트되지 않았습니다.따라서 주의하여 사용하십시오.

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;
}

react-router v6를 해야 .matchPath배열과 .모든 루트는 배열과 같은 변수에 저장해야 합니다.다음으로 모든 루트를 루프하고 그 기능을 사용하여 일치하는 루트를 찾을 수 있습니다.이 값은 첫 번째 truthy 값과 일치하므로 렌더링한 순서와 같은 순서로 루프를 반복해야 합니다.

같은 변수에 네스트된 루트를 저장하지 않으면 네스트된 루트를 처리할 수 없기 때문에 이 솔루션은 완벽한 솔루션이 아닙니다.

다음은 예를 제시하겠습니다.

routes.ts를 참조해 주세요.

const routes = [
  { name: 'Home', path: '/home', element: Home },
  { name: 'Profile', path: '/profile', element: Profile },
  { name: '404', path: '*', element: NotFound },
];

App.tsx

<App>
  <BrowserRouter>
    <Header />
    <Routes>
      {routes.map((route, key) => (
        <Route key={key} path={route.path} element={<route.element />} />
      ))}
    </Routes>
  </BrowserRouter>
</App

useMatchedRoute.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;
    }
  }
}

Header.tsx

export function Header() {
  const route = useMatchedRoute();

  return <div>{route.name}</div>
}

나는 Blazor와 c#에서 왔기 때문에 꽤 다르다.그래도 내 방식대로 할 것 같은데...

여기에서는 최신 버전의 리액트 라우터 돔(V6.3.0)을 사용하고 있습니다.

기본적으로 어레이 내의 모든 개인 루트 이름을 선언한 후 어레이에서 사용자가 의도한 경로를 검증합니다.

또한 라우터가 리다이렉트처를 알 수 있도록 isLogged 파라미터를 전달하고 있습니다.

로그인 컴포넌트에서 나중에 사용자가 원하는 위치를 알 수 있으며 로그인 후 사용자가 원하는 위치로 리다이렉트할 수 있습니다(이 예에서는 구현되지 않은 기능).

import {useRoutes, useNavigate, useLocation} from "react-router-dom";

export const RouteHandler = ({isLogged} : any) : any => {
let location = useLocation();
let navigate = useNavigate();

let privateRoutes : string[] = [
    "/dashboard",
    "/products"
    //add more private stuff here
];

if(privateRoutes.includes(location.pathname))
{
    if(!isLogged)
    {
        navigate(`/login?return=${location.pathname}`);
    }
}
else
{
    //will go to not found
}

return useRoutes([
    { 
        path: "/login", 
        element: <h2>Login component</h2>
    },
    { 
        path: "/dashboard", 
        element: <h2>You are now logged in</h2>
    },
    { 
        path: "*", 
        element: <h2>Page not found</h2>
    },
]);
}

사용법은 다음과 같습니다.

import {RouteHandler } from './mylocation';

<RouteHandler isLogged={true}/>

나는 그것이 미래에 몇몇 사람들에게 도움이 되기를 바란다.

리액트 라우터 v6의 경우:

import { matchPath, useLocation } from "react-router-dom";

const routes = ["/", "/login", "product", "product/:id"];

const usePathPattern = (): string | undefined => {
  const { pathname } = useLocation();
  return routes.find((route) => matchPath(route, pathname));
};

@RichN 님의 답변에 감사드립니다.나는 그의 답변을 개선/수정하고 리액트 라우터와 호환되도록 노력했다.

import { UNSAFE_RouteContext } from 'react-router-dom'
function usePathPattern () {
  let lastRouteContext = useContext(UNSAFE_RouteContext)
  while (lastRouteContext.outlet) lastRouteContext = lastRouteContext.outlet.props.routeContext
  return lastRouteContext.matches
    .map(({ route: { path } }) => path).filter(Boolean)
    .join('/').replaceAll(/\/\*?\//g, '/')
}

샘플 출력:

/:localeCode/:orgName/iaas/:projectSlug/vms/:vmUid/*

또는 다음 중 하나를 선택합니다.

  return lastRouteContext.matches.reduce((patternPath, { route: { path } }) =>
    patternPath + (path
      ? path.endsWith('*') ? path.slice(0, -1) : path.endsWith('/') ? path : path + '/'
      : ''
    ), '')

샘플 출력:

/:localeCode/:orgName/iaas/:projectSlug/vms/:vmUid/

그렇지만.....

... (저와 마찬가지로) 풀 패턴이 아닌 여기(사용처)까지 일치한 패턴을 알아야 하는 경우 마지막 패턴을 찾기 위해 루트 컨텍스트로 이동할 필요가 없습니다( )findLastNode@RichN's answer).

이것으로 충분합니다.

const useLocationPattern = () => useContext(UNSAFE_RouteContext).matches.reduce((patternPath, { route: { path } }) =>
  patternPath + (path
    ? path.endsWith('*') ? path.slice(0, -1) : path.endsWith('/') ? path : path + '/'
    : ''
  ), '')

샘플 출력:

 # In a near-to-root component:
/:localeCode/:orgName/
# In a very nested component (for the same URL):
/:localeCode/:orgName/iaas/:projectSlug/vms/:vmUid/

지금은 할 수 없습니다.다음으로 회피책을 제시하겠습니다.

<Route path="/:state" element={<LocationView />} />
<Route path="/:state/:city*" element={<LocationView city />} />

같은 컴포넌트를 여러 경로로 렌더링하려고 하는 것 같습니다.경로 패턴을 체크하는 대신 컴포넌트에 부울 프로펠러를 추가할 수 있습니다(이 경우).city) 및 프로펠러가 사실인지 확인합니다.

import { useMatch, Route, Routes } from "react-router-dom";

<Routes>
   <Route path="/" element={<Element1 match={useMatch("/")} />}  >
      <Route path=":id" element={<Element2 match={useMatch("/:id")} />}  />
   </Route>
</Routes>

질문에 대한 직접적인 답변은 아니지만, 이 질문을 얻으려고 노력하다가 이 질문을 발견한params에서match오브젝트, 이제 이 작업을 수행할 수 있습니다.useParams갈고리를 채우다

import { Route, Routes } from 'react-router-dom';
import { useParams } from 'react-router';

<Routes>
   <Route path="/:id" element={<MyComponent />} />
</Routes>

...

function MyComponent() {
  const { id } = useParams();

  return <div>{id}</div>
}

유용했으면 좋겠다.

언급URL : https://stackoverflow.com/questions/66265608/react-router-v6-get-path-pattern-for-current-route

반응형