reactjs - useMatch för flera mönster att testa på i react-router-dom


Jag har följande array:

const tabsList = [
  { 
    pathPattern: 'users/'
    label: 'Manage users'
  },
  {
    pathPattern: 'users/:id',
    label: 'Edit user profile'
  }
] 

Jag behöver en metod från react-router-dom för att tala om vilken av ovanstående arrayposter som matchar den aktuella sökvägen.

Baserat på det kommer jag att kunna färga det aktiva listobjektet i mina komponentstilar.

Jag hittade metoden useMatch() som verkar göra nästan vad jag vill, men den accepterar inte en array, den accepterar endast ett strängmönster att använda för jämförelse.

// example: current path is /users/82374023854321
const isAllUsersMatch = useMatch('/users') // null
const isUserIdMatch = useMatch('/users/:id') // { ...PathMatch<string> } 

det fungerar, men det är inte bra, jag måste skapa en separat variabel på det sättet för varje objekt i arrayen.

Finns det något liknande följande i react-router-dom?

const tabsList = [
  { 
    pathPattern: 'users/'
    label: 'Manage users'
  },
  {
    pathPattern: 'users/:id',
    label: 'Edit user profile'
  }
] 
const activeListItem = tabsList.some((listItem)=> doesItMatch(listItem.pathPattern))

Jag skulle ha gjort detta med hooken, men i React kan du inte använda en hook inuti en callback, så följande skulle inte fungera:

// const activeListItem = tabsList.some((listItem)=> doesItMatch(listItem.pathPattern))
const activeListItem = tabsList.some((listItem)=> useMatch(listItem.pathPattern)) // ERROR

Svar #1

Du är på rätt spår när du itererar över tabsList-arrayen. Om allt du behöver är att matcha den aktuella vägen med en i ett konfigurationsobjekt/array, kan du istället för att använda useMatch-hooken, som inte fungerar i en nästlad callback-funktion, använda matchPath-hjälpfunktionen som useMatch-hooken använder direkt.

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

const tabsList = [
  {
    pathPattern: "users/",
    label: "Manage users"
  },
  {
    pathPattern: "users/:id",
    label: "Edit user profile"
  }
];

...

const { pathname } = useLocation();
const activeListItem = tabsList.find(({ pathPattern }) =>
  matchPath(pathPattern, pathname)
);

Och ovanstående abstrakterat till en anpassad hook:

const useTabsListMatches = (tabsList = []) => {
  const { pathname } = useLocation();
  return tabsList.find(({ pathPattern }) =>
    matchPath(pathPattern, pathname)
  );
}
const activeListItem = useTabsListMatches(tabsList);

Svar #2

Du kan förmodligen använda react-router's matchRoutes() om du ändrar formen på ditt objekt:

const location = useLocation()

const matches = matchRoutes([{ 
  path: 'users/',
  label: 'Manage users',
}, {
  path: 'users/:id',
  label: 'Edit user profile',
}], location)

Relaterade artiklar