How to apply different layout to React Router routes
Most of the SaaS sites has a similar pattern, marketing pages, pages after login. Marketing pages may or may not share elements in terms of the layout, but the pages after login will share something like sub-nav, top nav, modules, things like that. I use React outer v5
with Typescript
. It is easy, but it took some time.
1. Requirements
The requirements are fair simple. The website has 3 sections:
Most of the routes needs to be lazy loaded.
- non-auth pages
- before login
- some of them share elements, and some don’t)
- a new user onboarding page
- after login
- only for new users
- not share any layouts with the pages that need auth.
- auth pages
- after login
- need a layout wrapper to share a common layout
2. Declare the routes constants
I thought this should be easy, but actually, it is not that easy.
1 | export const ROUTES = { |
The as const
will frozen ROUTES
, when you try to modify this, it will give you an error.
3. Declare the non-auth routes and auth routes
1 | const BEFORE_AUTH_CONFIG = { |
There are several ways to do the rendering, you can just compose the <Route>
component here. I prefer to use this plain object style, later on we will generate route component from this object. You can expand the data structure here, so you can pass more props to the factory method, but I found it fits my case.
The AuthRoutesLayout
is for the sharing part, the App
component contains the top level components that you want to share across pages.
4. Declare the special onboarding route
1 | const onBoardingRoute = ( |
Why this is not using the config style? Actually you can, but in my case, it is just this one page, and it needs some special logic when generic than the generic auth pages, I omitted them when writing the blog. But you get the idea.
5. Implement the ProtectedRoute
1 | import { Route, Redirect } from "react-router-dom"; |
The logic is easy, go to route if the user is authenticated, otherwise we go to the /login
page.
6. Transform the config object to a Route component
1 | import React from "react"; |
This is the Javascript version, pretty straightforward, we pass a boolean, so we know if it is a protected route or a normal route.
This is the Typescript version, it is mainly for type checking the config object, to make sure it has a key of string and lazy component as key.
1 | import React, { LazyExoticComponent, FunctionComponent } from "react"; |
7. The final composing
1 | export const Routes: React.FC = observer(() => { |
The previous 3 sections are all here. And we added a fallback path to <Redirect to={ROUTES.INDEX} />
, so when we hit the non-exist pages, we will route the user to the index page.
8. End
That’s all. Hope it helps.
Thanks for reading!
Follow me (albertgao) on twitter, if you want to hear more about my interesting ideas.