How to preserve query parameters in React Router links
Nick Scialli
July 02, 2021
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>
</>
);
}
Nick Scialli is a senior UI engineer at Microsoft.