Why can't I use querystrings in my router?

Viewed 53

I want to use the url path with the query string in the router as shown below.

//App.js
          <Route
            path={"/my_account"}
            component={Pages.account}
          />
          <Route
            exact
            path={"/support_main/notice?page=1"} Lik this!!!!!!!!!
            component={Pages.support_notice_list}
          />

// link.js
                  <Link to={"/support_main/notice?page=1"} className="menu-list-link">
                    <ListItemText
                      primary={item.text}
                      className="munu-list-text"
                    />

In this case, the page cannot be found.....:(

//App.js
          <Route
            exact
            path={"/support_main/notice"} OK
            component={Pages.support_notice_list}
          />

// link.js
                  <Link to={"/support_main/notice?page=1"} className="menu-list-link">
                    <ListItemText
                      primary={item.text}
                      className="munu-list-text"
                    />

In the above case, it works normally. Is there any way to use query string in router ?

1 Answers

Simply put, it's because RRDv5 deals only in matching the path, not any part of the query search string.

For route path matching, only the "/support_main/notice" is considered. To make this a bit more clear, here is a more conventional way to link to "/support_main/notice" and pass a search string. Here the path and search string are split up and explicitly passed.

<Link
  to={{
    pathname: "/support_main/notice",
    search: "?page=1"
  }}
>
  To notice
</Link>

When you link to "/support_main/notice?page=1" the search isn't part of the path matching.

Link to-object

to: object

An object that can have any of the following properties:

  • pathname: A string representing the path to link to.

  • search: A string representation of query parameters.

  • hash: A hash to put in the URL, e.g. #a-hash.

  • state: State to persist to the location.

    <Link
      to={{
        pathname: "/courses",
        search: "?sort=name",
        hash: "#the-hash",
        state: { fromDashboard: true }
      }}
    />
    

Consider the following code:

const Page1MatchPath = () => <h1>Page 1 matched by path</h1>;
const Page1MatchPathAndQuery = () => <h1>Page 1 matched by path and query</h1>;

export default function App() {
  return (
    <Router>
      <div className="App">
        <h1>Hello CodeSandbox</h1>
        <h2>Start editing to see some magic happen!</h2>

        <ul>
          <li>
            <Link to="/support_main/notice?page=1">To notice (string)</Link>
          </li>
          <li>
            <Link
              to={{
                pathname: "/support_main/notice",
                search: "?page=1"
              }}
            >
              To notice (object)
            </Link>
          </li>
        </ul>

        <Switch>
          <Route
            path={"/support_main/notice?page=1"}
            component={Page1MatchPathAndQuery}
          />
          <Route path={"/support_main/notice"} component={Page1MatchPath} />
        </Switch>
      </div>
    </Router>
  );
}

Edit why-cant-i-use-querystrings-in-my-router

Note that even though the full path and query string is listed first in the Switch that is doesn't match, and is skipped over and matched by path alone. In other words, it's too specific to match "/support_main/notice", and yet doesn't take the query string into consideration for matching.

But why don't query strings work in path prop?

This is very likely due to the way path matching is handled. Under-the-hood RRDv5 path props are strings that path-to-regex@^1.7.0 understands. In this specific case the "?" character is interpreted as an optional parameter.

Optional

Parameters can be suffixed with a question mark (?) to make the parameter optional. This will also make the prefix optional.

var re = pathToRegexp('/:foo/:bar?', keys)
// keys = [{ name: 'foo', ... }, { name: 'bar', delimiter: '/', optional: true, repeat: false }]

re.exec('/test')
//=> ['/test', 'test', undefined]

re.exec('/test/route')
//=> ['/test', 'test', 'route']

To also more firmly put it, the Usage outright also states in a note:

Please note: The RegExp returned by path-to-regexp is intended for use with pathnames or hostnames. It can not handle the query strings or fragments of a URL.

Related