How to route like a hacker with MobX and router5
Routing that fits your app — not the other way round
There are many ways to approach routing in client-side apps. Frameworks like Android provide powerful but also complex and sometimes restrictive routing mechanisms. The same applies to full-fledged routing libraries in the frontend like React Router.
The good news is that you can write your own routing layer that is simpler without giving up control: Routing that fits your app—not the other way around!
To illustrate these concepts, let’s write a HackerNews app and take control of routing. We will use React, MobX and router5.
This is the live result:
The example uses HNPWA API. Here’s the Github project.
Let’s start by defining the Feed route:
The properties name
, path
, and comp
are obvious. With link
you have type-assisted reverse routing. In the lifecycle function activate
, you update global state and perform API requests. The dependency store
is your central state management and action control panel. In the last line, you add FeedRoute
to your route registry routes
.
The cool thing about FeedRoute
is that everything relevant for routing to/from the Feed screen is defined in one place. Plus, you don’t need a container component for performing API requests.
Here’s how you render the current route:
The observable property store.route
contains the current route. In your route registry store.routes
you find the corresponding route definition. So, you know which component to render. If you’re on /
the component will be <FeedScreen/>
. By being an observer, App
rerenders whenever the observable store.route
changes.
That’s the gist!
Getting it set up
How do you set all this up with MobX and router5? Who updates the current route? What does store
look like? To find out, read on!
Aside: Although a routing library is not required, I do recommend router5. It gives you a more convenient API (+ hooks and utilities) than the browser’s native one.
The router5 plugin definition:
A router5 plugin implements lifecycle functions. On a successful transition, you deactivate the previous route. Then you set store.route
to the next route and activate the next route. Deactivation performs cleanup. Activation performs API requests and other initialization logic. The rest of the code is router5 API specific.
Here are the relevant parts from store
:
The selected feed is derived from the URL. There is no duplication of state thanks to MobX’s propagation power!
Aside: I use a special fetching helper which will be a topic for another article.
In my own HackerNews client (live), a history stack keeps track of the visited routes. It is used to render the screens on top of each other. All but the top-most screen have display
set to none
. This makes going back to the previous screen on mobile devices much faster!
My router also performs view state restoration. Think scroll position. But you can just as well keep it as minimal as shown here. Remember, you are in control of routing: do it in a way best suited to your app. See also React Router’s scroll restoration discussion and router5’s loading async data dicussion.
The presented approach is inspired by:
- How to decouple state and UI (you don’t need componentWillMount)
- A different approach to routing in Single-Page Applications
If you enjoyed this article, please recommend and share. Happy Routing!