TypeOfNaN

How to preserve query parameters in React Router links

Nick Scialli
July 02, 2021

New — Check out my free newsletter on how the web works!

react router

React Router makes front-end routing a breeze, but it’s not always obvious how to handle query parameters.

Let’s say you have a query parameter in your current route that represents a coupon on your commerce site:

https://www.mysite.com/some-route?coupon=abc123

Now, you have a link to the /checkout page:

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

function SomePage() {
  return (
    <>
      <p>Read to checkout?</p>
      <Link to="/checkout">Checkout</Link>
    </>
  );
}

Much to your chagrin, you realize that clicking this link erases the coupon code:

https://www.mysite.com/checkout

A one-time fix

Fortunately, React Router has a handy useLocation hook we can use to grab the query string. Here’s how it works:

import { Link, useLocation } from 'react-router-dom';

function SomePage() {
  const { search } = useLocation();

  return (
    <>
      <p>Read to checkout?</p>
      <Link to={`/checkout${search}`}>Checkout</Link>
    </>
  );
}

And that will work!

But what if you need this pattern of retaining any search parameters in multiple places or even site-wide? It would be a pain to keep adding this hook and associated to prop interpolation to every place you need it.

Writing a custom LinkWithQuery component

We can achieve the desired abstraction by writing a custom component:

import { Link, useLocation } from 'react-router-dom';

export const LinkWithQuery = ({ children, to, ...props }) => {
  const { search } = useLocation();

  return (
    <Link to={to + search} {...props}>
      {children}
    </Lonk>
  );
};

Note that this custom component, LinkWithQuery, takes the same arguments as a Link component. It then uses the useLocation hook to grab the search string. Finally, it concatenates to and search in the Link and additionally spreads other props you provide.

Now we can use this component instead of Link and be confident that any query parameters will be appended for us:

import { LinkWithQuery } from './LinkWithQuery';

function SomePage() {
  return (
    <>
      <p>Read to checkout?</p>
      <LinkWithQuery to="/checkout">Checkout</LinkWithQuery>
    </>
  );
}

🎓 Learn how the web works

One of the best ways to level up your tech career is to have a great foundational understanding of how the web works. In my free newsletter, How the Web Works, I provide simple, bite-sized explanations for various web topics that can help you boost your knowledge. Join 2,500+ other learners on the newsletter today!

Signing up is free, I never spam, and you can unsubscribe any time. You won't regret it!

Sign up for the newsletter »
Nick Scialli

Nick Scialli is a senior UI engineer at Microsoft.

© 2024 Nick Scialli