2

Assume I have the following pages on my website

  • Page 1: example.com/somepage.php?action=a
  • Page 2: example.com/somepage.php?action=b
  • Page 3: example.com/somepage.php?action=b&other=c

IMPORTANT NOTE: I do not have control of the URL paths, this is how they are set, and this is why they are far from ideal.

I am creating a React app, and I am trying to set routing, so here is what I started with:

function MyNav () {
    return (
        <Routes>
            <Route path='/somepage.php?action=a' element={<Page1 />} />
            <Route path='/somepage.php?action=b' element={<Page2 />} />
            <Route path='/somepage.php?action=b&other=c' element={<Page3 />} />
            <Route path='*' element={<Page1 />} />
        </Routes>
    )
}

But this did not work. After investigation, and after looking into the window.location object, it turned out that path in <Route/> will be compared to location.pathname. So, for all the pages above, the window.location object will look as follows:

window.location
    ...
    pathname: "/somepage.php"
    search: "?action=a" // <-------- this is for Page 1, and will be different for Page 2 and Page 3
    ...

So, the route for Page 1, should be set as follows

<Routes>
    <Route path='/somepage.php' element={<Page1 />} />
    ...
</Routes>

But this would create a problem, because it will be the same route for all pages, as follows:

<Routes>
    <Route path='/somepage.php' element={<Page1 />} />
    <Route path='/somepage.php' element={<Page2 />} />
    <Route path='/somepage.php' element={<Page3 />} />
    <Route path='*' element={<Page1 />} />
</Routes>

Now, to solve the problem above, I found this solution, so I modified my code a little, as follows

function MyNav () {
    
    const getPage = (location) => {
        
        const params = new URL(location.href).searchParams;
        const action = params.get('action');
        const other = params.get('other');
        
        if (action == 'a') {
            return <Page1 />
        }

        if (action == 'b') {
            if (other == 'c') {
                return <Page3 />
            }

            else {
                return <Page2 />
            }
        }
    }
    
    
    return (
        <Routes>
            <Route path='/somepage.php' element={ getPage (location) } />
            <Route path='*' element={<Page1 />} />
        </Routes>
    )
}

Now this works (yay!), however it defeats the purpose of the path prop in <Route/>. So, is there a way to directly search for the search parameters from within <Route/>? Maybe something like this? (IMPORTANT: THE FOLLOWING IS PSEUDO CODE)

<Routes>
    <Route path='/somepage.php' params='action=a' element={<Page1 />} />
    <Route path='/somepage.php' params='action=b' element={<Page2 />} />
    <Route path='/somepage.php' params='action=b&other=c' element={<Page3 />} />
    <Route path='*' element={<Page1 />} />
</Routes>
Greeso
  • 7,544
  • 9
  • 51
  • 77
  • No. RRD only concerns itself with the path part of the URL with regards to route matching. Your middle implementation is the closest to being correct. – Drew Reese Jan 31 '23 at 01:37
  • 1
    Just wondering if you only need to read the query param if `useSearchParams` does what you need here and is more succinct? [Example: https://codesandbox.io/s/use-search-params-example-ki94mc](https://codesandbox.io/s/use-search-params-example-ki94mc) – abgregs Jan 31 '23 at 02:01
  • 1
    This isn't particularly better than what you have but it leverages the react-router API: https://v5.reactrouter.com/web/api/match. And at least you get access to the params from the match rather than having to do `new URL(location.href).searchParams;` – nbermudezs Jan 31 '23 at 02:10
  • 1
    @nbermudezs - Thanks for the suggestion. I have not used it before. I will look into that. – Greeso Jan 31 '23 at 14:04

1 Answers1

1

RRD only concerns itself with the path part of the URL with regards to route matching. Your middle implementation is the closest to being correct. The best you can do is to render a single route that matched by the URL path, and check the queryString in a routed component. I'd suggest refactoring it into its own component that reads the queryString though and conditionally returns the correct component.

Example:

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

const Page = () => {
  const [searchParams] = useSearchParams();
  const action = searchParams.get("action");
  const other = searchParams.get("other");

  switch(action) {
    case "a":
    default:
      return <Page1 />;

    case "b":
      switch(other) {
        case "c":
          return <Page3 />;

        default:
          return <Page2 />;
      }
  }
};
<Routes>
  <Route path='/somepage.php' element={<Page />} />
  <Route path='*' element={<Page1 />} />
</Routes>
Drew Reese
  • 165,259
  • 14
  • 153
  • 181