Search code examples
reactjsreact-routerfrontendreact-router-dom

Can I match any of possible route matches with react router dom 6?


I have 3 possible paths that can be under one path. Is there any method that I can match all possible matches?

For example, the code as-is like

const MyComponent = () => {
  const firstMatch = useMatch('/:appId/:firstKey');
  const secondMatch = useMatch('/:appId/:firstKey/:secondKey');
  const thirdMatch = useMatch('/:appId/:firstKey/:secondKey/:thirdKey');

  if (firstMatch == null && secondMatch == null && thirdMatch == null) {
    return <Navigate to="/" replace={true} />;
  }
  const firstKey =
    (firstMatch?.params.firstKey) ||
    (secondMatch?.params.firstKey) ||
    (thirdMatch?.params.firstKey);

  return ....

pseudo-code should be..

const firstMatch = useMatch('/:appId/:firstKey?/:secondKey?/:thirdKey');

But I found that the question mark pattern is removed as of version 6.

Do I have better option?


Solution

  • Optional path params are available for the Route component's path prop, but for the time being they are incompatible with the useMatch hook and matchPath utility function. There is a filed github issue & discussion regarding processing optional path segments in these hooks and utilities.

    If you are looking for something a little more DRY than using three separate useMatch hooks then I'd recommend loading the paths you want to match into an array and iterating over each, checking the path with the matchPath utility function.

    The logic may look similar to the following:

    const patterns = [
      "/:appId/:firstKey/:secondKey/:thirdKey",
      "/:appId/:firstKey/:secondKey",
      "/:appId/:firstKey"
    ];
    
    const MyComponent = () => {
      const { pathname } = useLocation();
    
      const match = patterns.reduce(
        (match, pattern) => (match ? match : matchPath(pattern, pathname)),
        null
      );
    
      if (!match) {
        return <Navigate to="/" replace />;
      }
    
      const { firstKey } = match.params;
    
      return (
        ....
      );
    };
    

    Edit can-i-match-any-of-possible-route-matches-with-react-router-dom-6

    Since optional path segments work, it might just be easier to only match the routes you want to begin with.

    Example:

    const MyComponent = () => {
      const { firstKey } = useParams();
    
      return (
        ...
      );
    };
    
    <Routes>
      ....
      <Route
        path="/:appId/:firstKey/:secondKey?/:thirdKey?" // <-- firstKey required
        element={<MyComponent />}
      />
      ....
      <Route path="*" element={<Navigate to="/" replace />} />
    </Routes>
    

    Edit can-i-match-any-of-possible-route-matches-with-react-router-dom-6 (forked)