Protected Routes in React Router v6

Protected Routes in React Router v6

Two simple ways to set up private routes in your react project

·

5 min read

Table of contents

Introduction

The new React Router v6 update brought a lot of changes, while also stripping away some functionalities. One of these changes we will focus on is how you set up protected or private routes. For those who do not know, a private route (also called a protected route) is a route/component in an application that is only available to a user after a specific condition is met. For example, a user's dashboard is only accessible to the user if he/she is logged in.

Private Routes In v5

The previous version of react-router allowed you to nest components and also use a function called Redirect to redirect users based on a given condition. With this, the common way of setting up private routes is as follows:

  <switch>
    <Route exact path='/'>
      {!user && <Redirect to='/login' />}
      {user && <Dashboard />}
    </Route>
    <Route path='/login'>
      {user && <Redirect to='/' />}
      {!user && <Login/>}
    </Route>
  </switch>

Notice that all routes are inside the switch component and the base URL must include an exact prop if not it would be considered a match to any URL entered by the user and thus would always be displayed no matter the path. Inside the first route component, we check if we have a user (assuming the user variable represents a user object); if it is false we redirect the user to the login route, otherwise we render the homepage. The purpose of the second route definition is to make sure that a user is not allowed to access the login page if he/she is already logged in.

Private Routes In v6

One of the major changes with version 6 is that the switch component has been replaced with a Routes component, and the exact prop has been removed as the router automatically matches only one route with a complete match. The new update also requires that all children of the routes component must be individual routes. Another change is that Redirect has been replaced with Navigate, which works a bit differently.

Using Outlet

The new update also added another component called Outlet which you can use to create a child route. However, for this to work, you need to create a separate component in which you'll conditionally pass an Outlet to a component, then add the component as an element parameter to a route. We're going to call this route PrivateRoutes in case we might want to use it multiple times (you can use any name of your choice):

import { Navigate, Outlet } from 'react-router-dom'

const PrivateRoutes = () => {
  const { user } = AuthContext()

return (
    user ? <Outlet/> : <Navigate to='/login'/>
  )
}

Now we can import and use this component in our routes as follows:

  <Routes>
      <Route element={<PrivateRoutes/>}>
          <Route path='/' element={<Home/>} />
      </Route>
      <Route path='/login' element={<Login/>}/>
  </Routes>

This method is particularly useful when the same rule applies to multiple routes (e.g. the home and product page which you might want to make accessible only when the user is logged in). One disadvantage of this method as you might have observed is that if we want to set two different conditions as we did we the example on version 5, we would have to create two different components to handle those conditions. This leads to more code and can also be confusing at times; that is why I like to use this second method of achieving this.

Using The Ternary Operator

This method is very straightforward and simple:


<Routes>
  <Route element={user ? <Home /> : <Login />} path="/" />
  <Route element={!user ? <Login /> : <Home />} path="/login" />
</Routes>

With this method, when the user goes to the base URL, we check if they are already logged in. If we have a user object (meaning the user is logged in), we render the homepage; else we render the login page for the user to log in. The same condition applies to the second route.

The Caveat

One thing you might have noticed from the example above is that, while we passed two different components to be rendered alternatively, the path is still the same, which means that whichever component is being rendered, the path (the URL displayed by the browser) is still the same. Thus if the login page was rendered, the browser still displays the base URL meant for the homepage and likewise for the second route. I'm not aware of any security risks imposed by this (if you do please share in the comments section below). However, some people might not be comfortable with this, if you're one of those people, I would advise you to use the first method.

Conclusion

There are many ways to kill a rat!

The above quote is a statement I heard from a friend a few years back which still rings in my mind to this day because of how it applies to most of the things we do each day. When it comes to programming, it's really hard to state which method is the absolute best; it is mostly based on preferences. I'm sure the two methods I shared above are not the only ways of setting up private routes, it's left for you to decide which method works for you.

Thanks for reading!

Did you find this article valuable?

Support Paul Saje by becoming a sponsor. Any amount is appreciated!