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=abc123Now, 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/checkoutA 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.