Frontend Routing
The Basics
Routing, essentially rendering the correct content for the current URL and user, primarily takes place in the App component.
Using React Router, we can render the correct
component for the current URL easily with the Route
component:
1 |
|
Here, if the application's path is Routes.LANDING
, then Route
will render the Landing
page. (If it isn't, it'll render null).
Now consider a simplified version of our application with four declared paths. If we just had
four Route
s, then if the URL matched more than one of those paths, we would render more
than one component. However, in our App, we only want to render one page at a time. To accomplish
this, we use React Router's Switch
component:
1 2 3 4 5 6 |
|
Switch
looks for a Route
that matches the current path (in top-down order), then renders its
component and nothing else.
Auth Redirects
So far, so good. However, a user who isn't logged in shouldn't be able to go to the home page. Similarly, only admin users should have access to the admin dashboard. How can we ensure that users go to the appropriate pages based on their privilege level?
First, we have to get the user's privilege level using our Redux selector.
1 2 3 |
|
Then, we just use a switch statement to return the correct Switch
and Route
s.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
What do the routes actually look like?
Let's start with the user that isn't logged in. This user should be able to go to the Landing and
Login pages, but not the Home or Admin Dashboard pages. If they try to go to either of these pages,
we should redirect them to the Login page. Luckily for us, React Router has a Redirect
component
too. So we have:
1 2 3 4 5 6 |
|
If a user tries to go to the home page, we'll redirect them to Routes.LOGIN
and our second
Route
component will render the Login
page.
Redirecting Back After Login
But wouldn't it be great if we could send the user back to the page they originally wanted to go to
after they log in? Well, we can do that with React Router's location
, which represents "where the
app is now, where you want it to go, or even where it was" (according to the docs). Instead of
passing Redirect
's to
parameter a string (Routes.LOGIN
), we can pass it a location.
Then, instead of
1 |
|
we'll have
1 2 3 4 5 6 7 8 9 |
|
so the user will still go to Routes.LOGIN
, but our Login page will be able to access this state
property and learn that the user wanted to go Routes.HOME
.
We can abstract this Redirect
with location logic into a component that we'll call
AuthRedirect
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
Note
location.state
can have any props. We decided to name our redirect prop destination
, which
we declare in the following interface (located in App):
1 2 3 |
|
Then, after the user logs in, we can redirect the user to the home page.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
and finally, for our PrivilegeLevel.NONE
user we have:
1 2 3 4 5 6 7 8 9 |
|
Note
There are other ways to do this, namely by using path parameters and/or query parameters.
For instance, instead of having our AuthRedirect
, we could do something like:
1 |
|
Then in Login
, we'd do something like:
1 2 3 4 5 6 7 8 9 10 11 |
|
Why use this way?
The primary reason is that location
isn't shared across different tabs/browsers. So if you
open a new Login tab, the app won't redirect you to your original destination. But if you
open a new Login tab with the same query param (which you would get if you copy/pasted the
link), it will.
The catch
Users have access to the URL–they can mess with the query params and break things. Also, people tend to copy URLs directly when they share them, meaning they tend to share the query params. That's fine in some cases, but not when you don't want to share the query param behavior across any two random users.
Finishing up App
Just a little more to go! Thankfully, our standard and admin-level routing is pretty straightforward:
Standard users are redirected from the Admin Dashboard to Home:
1 2 3 4 5 6 |
|
and admins can go anywhere:
1 2 3 4 5 6 |
|
Then we just throw it all into React Router's BrowserRouter
component that syncs the
application to the browser's URL and put everything in App!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
|