Stateful URL with React and Redux

Sergii Karpiak, CEO / Full Stack Developer at Bitcom Systems on 2018-12-17

When building a web app, we aim to provide the best user experience possible. One of the issues the users can face is that you can’t share the URL with the exact same layout and data with other users.

Usually when you share a SPA URL with someone, they will open it in a general view, and won’t see those filters that you specifically want to show. So, if you want to share a particular part of the page (let’s say scrolled to some point, and had some information filtered), will need a stateful URL to achieve this.

By stateful URL we mean a URL having query parameters. These parameters contain view specific information, like scroll, filters etc, which in essence is a state of the web app layout.

In this post we will see how and when to use URL query to store app state and parse query strings with React Router.

React app State

React and Redux are super powerful tools for managing global application state. Let’s see how to do the exact same thing using the URL and react-router.

Why URL

Usually when we create single page application, the URL does not really matter. In most cases, it is just an endpoint to request all the assets and that’s it. Let’s change that and see how helpful it can be for our app.

How URL can help

By adding parameters after ‘?’ in the URL we can store data similar to Redux. Now that we have two storage places, let’s see which data to store in what place and why.

I like to split user application state into two logical parts:

  • client side state - everything related to how page looks like: selected tab, sorting, filtering, etc;
  • server side state - data content which user can see and edit.

It is better to store client side state data in URL. This approach gives us next benefits:

  • user experience, you can copy URL and send to other users, and when somebody opens this URL, the page will be displayed with exactly the same search, filtering and sorting data.
  • testability, this effect is also helpful for test automation as most testing tools support working with URLs.

Access URL query values

React-router allows you to access it via this.props.location.search, but it does not parse the query. Query-string library allows you to parse and stringify URL query in an easy way.

Example

Let’s create a simple example and see how to implement and parse query strings with Query-string and React Router.

url example

This URL has four query strings parameters which require to display first 50 active users. Let’s try and build the Route for the URL above. It may look like this:

1
<Route <path={`test/dashboard/users`} component={UserList} />

We don’t take into account the query string when we create the Route. We will need to parse the query inside the component that is being rendered when that path matches - in this case, users.

We’re assuming the URL looks like this:

1
http://test/dashboard/users?filter=active&order=ascend&page=1&pageSize=50

1
2
3
4
5
6
7
8
class UserList extends Component {
componentDidMount() {
// How do we get the values for filter, order, page and pageSize?
}
render() {
...
}
}

How do we get access to the query string values from the URL? If you check around on the location object that is passed to all components rendered by React Router, you’ll notice that it has a search property in it.

1
2
3
4
componentDidMount() {
console.log(this.props.location.search)
// "filter=active&order=ascend&page=1&pageSize=50"
}

Query-string library will help us parse the query.

1
2
3
4
5
6
7
8
9
10
11
import queryString from 'query-string'

...

componentDidMount() {
const values = queryString.parse(this.props.location.search)
console.log(values.filter) // "active"
console.log(values.order) // "ascend"
console.log(values.page) // "1"
console.log(values.pageSize) // "50"
}

Now we can parse the URL query.

The Stateful URL is a simple way to substantially improve user experience in web apps.

For more information on creating your mobile and web apps, please contact us Bitcom Systems.