Search code examples
javascriptreactjsreact-router-dom

React-Router-Dom v6 How do I match subpages. I was on v5


I found that I am having to reorganize my routes switching from React-Router-Dom v5 to v6.

I have this outer route:

<Route
  path="/abc/product/:skuType/:skuPage?"
  element={
    <PrivateRoute>
      <ProductRoutesStructure />
    </PrivateRoute>
  }
/>

But none of my routes are matching. So I am unsure how to match. For instance, in one route, it looks like this: 'abc/product/1234/converse'

and I am doing this:

export const ProductRoutesStructure = () => (
  <Routes key="productRoutes">
    <Route
      path={`/abc/product/:skuType/:skuPage(${Types.CONVERSE})`} 
      element={<SneakerPage />}
    />
    <Route
      path={`/abc/product/:skuType/:skuPage(${Types.PANTS})`} 
      element={<PantsPage />}
    />
    <Route path="*" element={<GenericPage />} />
  </Routes>
)

The things is that skuType and skuPage must be dyanmic as in those element components since I hit certain APIs. I just am really needing to match on the skuPage.

I think I am missing some nuance of sub pages. I tried matching on just "Types.CONVERSE", but that is a no go, it always defaults to the last bit "*" catch-all route.

This is what I am expecting and this most certainly worked in v5, as this is actual code I used (pathing is different/names). But exactly the same. Worked like a charm, but v6, nope.

So, if a user goes to "www.myDomain/abc/product/male/converse"

I expect that to match this route:

<Route
  path={`/abc/product/:skuType/:skuPage(${Types.CONVERSE})`} 
 element={<SneakerPage />}
/>

If a user goes to "www.myDomain/abc/product/female/pants"

It would match:

<Route
  path={`/abc/product/:skuType/:skuPage(${Types.PANTS})`}
  element={<PantsPage />}
/>

But lets just make it work. I have no problem altering my routes in ProductRoutesStructure, but I tried a bunch of combinations, and nothing is matching.

Mind you, I do need skuType and skuPage to be available to child components/pages, that is why I need it in the base route.


Solution

  • From what I understand you have basically this "/abc/product/:skuType/:skuPage" route path that you'd like to match and render dynamic content on.

    Suggestion 1

    Render a single "/abc/product/:skuType/:skuPage" route and use a regular old Javascript switch statement to conditionally render the correct routed content based on the skuPage route path parameter.

    Outer Route

    <Routes>
      <Route
        path="/abc/product/:skuType/:skuPage"
        element={
          <PrivateRoute>
            <ProductRoutesStructure />
          </PrivateRoute>
        }
      />
    </Routes>
    

    ProductsRoutesStructure

    import { useParams } from 'react-router-dom';
    
    const ProductRoutesStructure = () => {
      const { skuPage } = useParams();
    
      switch (skuPage) {
        case Types.CONVERSE:
          return <SneakerPage />;
    
        case Types.PANTS:
          return <PantsPage />;
    
        default:
          return <GenericPage />;
      }
    };
    

    The routed content components use the useParams hook to access their route parameters.

    const SneakerPage = () => {
      const { skuPage, skuType } = useParams();
    
      return (
        <>
          <h1>SneakerPage</h1>
          <div>{skuType} - {skuPage}</div>
        </>
      );
    };
    
    const PantsPage = () => {
      const { skuPage, skuType } = useParams();
    
      return (
        <>
          <h1>PantsPage</h1>
          <div>{skuType} - {skuPage}</div>
        </>
      );
    };
    

    Demo 1

    Edit react-react-dom-v6-how-do-i-match-subpages-i-was-on-v5

    enter image description here

    Suggestion 2

    Render each specific skuPage directly, passing the skuPage value down as props to the routed content components.

    Outer Route

    <Routes>
      <Route
        path="/abc/product/:skuType/*" // <-- wildcard matcher for descendent routes
        element={
          <PrivateRoute>
            <ProductRoutesStructure />
          </PrivateRoute>
        }
      />
    </Routes>
    

    ProductRoutesStructure

    const ProductRoutesStructure = () => (
      <Routes key="productRoutes">
        <Route
          path={Types.CONVERSE}
          element={<SneakerPage skuPage={Types.CONVERSE} />}
        />
        <Route path={Types.PANTS} element={<PantsPage skuPage={Types.PANTS} />} />
        <Route path="*" element={<GenericPage />} />
      </Routes>
    );
    
    const SneakerPage = ({ skuPage }) => {
      const { skuType } = useParams();
    
      return (
        <>
          <h1>SneakerPage</h1>
          <div>
            {skuType} - {skuPage}
          </div>
        </>
      );
    };
    
    const PantsPage = ({ skuPage }) => {
      const { skuType } = useParams();
    
      return (
        <>
          <h1>PantsPage</h1>
          <div>
            {skuType} - {skuPage}
          </div>
        </>
      );
    };
    

    Demo 2

    Edit react-react-dom-v6-how-do-i-match-subpages-i-was-on-v5(version 2)

    enter image description here