Article summary
I’ve been working on a project where we wanted to implement a set of filters for a list of records on one page of our React web app and store the selected filters as state in the URL. We chose this approach so we could link directly to the page with specific filters selected. Adding the filter values to the query string in the URL offered a reasonable solution.
If you are a web developer, chances are that you’ve worked with query strings before. Handling them in React Router is similar to other framework tooling and is simple to learn for query string first-timers. If you are new to React Router or want a refresher on how to retrieve and parse query strings, this guide is for you.
Query Strings 101
Query strings are commonly used for embedding parameters into a URL. A typical query string might look like this:
https://search.com/?q=react&ia=web
The query string follows the ?
, and multiple parameters are separated by a delimiter–in this case an &
. These are typically key-value pairs, but it is possible to embed complex objects or arrays into the URL in the query string. The query string can contain any useful information, such as search strings, filter values, or any transient data that needs to be shared across pages.
Query Strings in React Router
React Router gives developers the freedom to do whatever makes sense for their application. It has moved away from including built-in query string parsing; instead of trying to satisfy everyone’s needs, it lets users handle their own implementation. The good news is that it is pretty straightforward.
1. Getting started
Let’s say you have a component that shows a searchable list of products, with an optional filter for items on clearance. The route for this page looks like: https://shopping.com/products/
. To include the search string and filter value in the URL, we want to have a query string that looks something like this:
https://shopping.com/products?q="shoes"&clearance=true
The route definition will look like this:
<Route exact path={"/products"} component={ProductsRouteLoader} />
And, using the loader pattern, the component could look like this:
import { asyncComponent } from "client/async-component";
import * as React from "react";
import { RouteComponentProps } from "react-router-dom";
export const ProductsRouteLoader = asyncComponent({
resolve: async () => {
const Search = (await import(
"client/pages/products"
)).Products;
const Wrapper: React.FunctionComponent<
RouteComponentProps
> = props => {
// Access query params here
// and pass them down to rendered component
return (
...
);
};
return Wrapper;
},
name: "ProductsPage",
});
2. Access router params
Next, we need to access the params stored in the URL.
React Router passes along a few objects in props: history
, match
, and location
. The one we care about is location
because it contains the information about the query params.
Here is what the object looks like:
location: {pathname: "/products", search: "?q="shoes"&clearance=true", hash: "", state: undefined, key: "eltjl1"}
Now we know we can get the query string via props.location.search
, but we can’t exactly do anything with it yet. So, the next step is parsing.
3. Choose a method
Method 1: DIY with browser API
Choose this method if…
- You’re targeting modern browsers that support the URL API. Check here
- You prefer a lighter-weight browser implementation rather than an external library.
- You need to handle parameters uniquely.
- You want to leverage TypeScript.
For most modern browsers, you’ll have access to the URL API, meaning you can handle parsing yourself using URLSearchParams
. Once you have a new URLSearchParams
object, there are many methods available to work with the query string of your URL. In most cases, all you’ll need is to call the get()
method with the key of the parameter you wish to access.
Rather than simply passing in a raw string key value, you can leverage types for added safety. The types for this route might look like this:
export namespace ProductsRoute {
export enum QueryParamKeys {
q = "q",
clearance = "clearance",
}
export type QueryParams = {
q: string;
clearance: boolean;
};
const path = `${PATH_TEMPLATE}?${QueryParamKeys.q}=${q}&${QueryParamKeys.clearance}=${clearance}`;
return generatePath(path)
}
We can pass ProductsRoute.QueryParamKeys.q
or ProductsRoute.QueryParamKeys.clearance
into the parse function and be assured that the keys are valid.
import { asyncComponent } from "client/async-component";
import * as React from "react";
import { RouteComponentProps } from "react-router-dom";
export const ProductsRouteLoader = asyncComponent({
resolve: async () => {
const Search = (await import(
"client/pages/products"
)).Products;
const Wrapper: React.FunctionComponent<
RouteComponentProps
> = props => {
const searchTerm = query.get(
ProductsRoute.QueryParamKeys.q
);
const clearance = stringToBool(query.get(
ProductsRoute.QueryParamKeys.clearance
));
return (
...
);
};
return Wrapper;
},
name: "ProductsPage",
});
Gotcha: When handling Boolean params, the get()
method will return the string value `true` or `false`, which are both truthy. A simple helper function can make it much easier to correctly handle string Boolean values.
Method 2: Let a third-party library handle it
Choose this method if….
- You’re targeting browsers that do not support the URL API, such as IE. Check here
- No special handling is needed.
React Router recommends using a library such as query-string
, which is available on npm if you are unable to use the built-in browser implementation of the URL API. Run yarn add query-string
to add and install it. Parsing query strings is then as simple as passing location.search
into the parse()
function.
import { asyncComponent } from "client/async-component";
import * as React from "react";
import { RouteComponentProps } from "react-router-dom";
import * as QueryString from "query-string"
export const ProductsRouteLoader = asyncComponent({
resolve: async () => {
const Search = (await import(
"client/pages/products"
)).Products;
const Wrapper: React.FunctionComponent<
RouteComponentProps
> = props => {
const params = QueryString.parse(props.location.search);
console.log(params.q); // "shoes"
console.log(params.clearance); // true
return (
...
);
};
return Wrapper;
},
name: "ProductsPage",
});
Conclusion
Query strings add seamless functionality and usability to web applications by passing data between pages via the URL. With React Router, parsing these query strings is made simple with third-party libraries or using the browser-based implementation of the URL API.
This is good but please can u rewrite it in javascript because it seems we am struggling to understand what you have written .You can forward it to my email and i will appreciate it .
Keep it up but please we want it in javascript .
Hi Samson,
Thank you for reading this post! To convert to Javascript, simply remove the type signatures and it might look more familiar. Good luck!
I like your writing style, keep up the great work!
Thanks, Tony! Glad you enjoyed it.
How can we add dynamic values to query param
ex.
this.handleCourseClicked(course.id)}>{course.title}
course_title should be dynamic as Im trying to prepare map object. So I want to insert course title dynamically. Please suggest. Thanks in adv.
Interesting approach, have you deliberately avoided using the inbuilt `URLSearchParams` object? ie
“`
import { useLocation } from “react-router-dom”;
function useQuery() {
return new URLSearchParams(useLocation().search);
}
“`
* https://betterprogramming.pub/using-url-parameters-and-query-strings-with-react-router-fffdcea7a8e9
Hi Peter, thank you for mentioning this! It looks like
useLocation
is new since I wrote this post, and I would definitely recommend using it.oohhh the distinction is in how the url string is accessed, i missed that, thanks for clearing it up :)
I think there is a bug in your code. You should use `window.location.search` instead of props.location.search, there are different objects and the first one is the one that contains the query string.