TL;DR: React Router 4 is a body of navigational components that offers declarative routing in your React apps. In this tutorial, you are going to learn how to use React Router 4 through practical examples.


Routing is of uttermost importance in almost every application's architecture. The larger your app becomes, the more your routing functionality becomes complex, from simple to deeply nested routing scenarios.

React Router is the most popular and commonly used library for routing in React applications. As your application grows to require several views and routes, it's ideal you choose a good router to help manage the transition between views, redirects, getting URL parameters easily, et al.

"React Router is the most popular and commonly used library for routing in React applications. "

Before now, previous versions of React Router involved declaring your app's routes upfront, declaring all the routes in a file as part of your app's initialization before rendering occurs. With React Router 4, you get to route declaratively. React Router 4's API is basically just components thus making it easy to use if you already compose components in React. Let's dive in!

Setup and Installation

You'll need:

React Router is composed of these packages: react-router, react-router-dom, and react-router-native.

  • react-router: comprises of the core routing components.
  • react-router-dom: comprises of the routing API required for browsers.
  • react-router-native: comprises of routing API for mobile applications.

Create a new project with create_react_app and navigate to the directory created as shown below:

create-react-app bose
cd bose

Install react-router-dom.

npm install --save react-router-dom

What we'll cover

We'll focus on using React Router 4 for the browser. We'll cover the very important concepts listed below:

  • Basic Routing
  • Nested Routing and URL Parameters
  • Route Protection and Authentication
  • Link Component Customization
  • Handling Non-existent Routes
  • SideBar Rendering

Basic Routing

There are two types of Router components that you can use in your React web application. The BrowserRouter and HashRouter. The former gives you a URL without the #, while the latter gives you a URL with the #.

Note: If you are building a web application that supports legacy browsers, it's recommended that you use the HashRouter.

Open up your src/index.js and add the code below to it:

import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';

ReactDOM.render(
  <Router>
    <App />
  </Router>, document.getElementById('root'));
registerServiceWorker();

In the code above, I imported the BrowserRouter, Route, and Link component from react-router-dom. And I wrapped the <App/> component with Router which is the alias of BrowserRouter. The Router component is the first step to routing successfully. It serves as the container for every other route component. Furthermore, the Router component can only have one child element or component. Now, how do we define our routes?

Open up src/App.js. Here, we will define our routes.

import React, { Component } from 'react';
import { Route, Link } from 'react-router-dom';
import './App.css';


const Home = () => (
  <div>
    <h2> Home </h2>
  </div>
);

const Airport = () => (
  <div>
     <ul>
      <li>Jomo Kenyatta</li>
      <li>Tambo</li>
      <li>Murtala Mohammed</li>
    </ul>
  </div>
);

const City = () => (
  <div>
    <ul>
      <li>San Francisco</li>
      <li>Istanbul</li>
      <li>Tokyo</li>
    </ul>
  </div>
);

class App extends Component {
  render() {
    return (
      <div>
        <ul>
          <li><Link to="/">Home</Link></li>
          <li><Link to="/airports">Airports</Link></li>
          <li><Link to="/cities">Cities</Link></li>
        </ul>

        <Route path="/" component={Home}/>
        <Route path="/airports" component={Airport}/>
        <Route path="/cities" component={City}/>
      </div>
    );
  }
}

export default App;

In the code above, we have links that should direct the user to /, /airports, and cities using the <Link> component. Each of these links has a component that should be rendered once the current location matches the route's path. However, something is off here. Let's check the results.

Airports route Airports route

Home which is the UI for Home component should be rendered only on the /, root route. However, it is rendered on all the routes. The / matches /airports and /cities routes, therefore rendering its component in these two other routes. The solution to this is to simply add the exact prop to the / route.

src/App.js

<Route path="/" exact component={Home}/>
<Route path="/airports" component={Airport}/>
<Route path="/cities" component={City}/>

Airports route with exact component rendering The Airports route without rendering Home component UI

In the examples above, all the <Route /> components have a component prop that renders a component when the URL visited matches the Route's path. What if you just want to render a small function instead of a whole component? You can use the render prop as shown in the code below.

<Route path="/airports" 
       render={() => (<div> This is the airport route </div>)}/>

Nested Routing & URL Parameters

What if you needed URLs like /courses/business, and /courses/technology/? How would you accomplish this?

src/App.js

import React, { Component } from 'react';
import { Route, Link } from 'react-router-dom';
import './App.css';


const Courses = ({ match }) => (
  <div>
     <ul>
        <li><Link to="/courses/technology">Technology</Link></li>
        <li><Link to="/courses/business">Business</Link></li>
        <li><Link to="/courses/economics">Economics</Link></li>
    </ul>


    <Route exact path="/courses/technology" render={() => (<div> This is technology </div>)}/>
    <Route path="/courses/business" component={() => (<div> This is business </div>)}/>
    <Route path="/courses/economics" component={() => (<div> This is economics </div>)}/>
  </div>
);

/* Home Component */ // code hidden

/* City Component */ //code hidden

class App extends Component {
  render() {
    return (
      <div>
        <ul>
          <li><Link to="/">Home</Link></li>
          <li><Link to="/courses">Courses</Link></li>
          <li><Link to="/cities">Cities</Link></li>
        </ul>

        <Route path="/" exact component={Home}/>
        <Route path="/courses" component={Courses}/>
        <Route path="/cities" component={City}/>
      </div>
    );
  }
}

export default App;

If the URL location matches the /courses path, then the technology, business, and economics links are rendered via the Courses component. Going one step further, if the URL location matches /courses/technology, /courses/business, and /courses/economics path, then This is technology, This is business, and This is economics are rendered respectively.

As a developer, I'm sure you are already looking at this approach with a set of refactoring eyes. In the code sample above, there's a lot of repetition and hardcoding. The more the lines of code, the harder it becomes to change a route. Let's refactor.

React Router 4 ships with a match API. The match object is created when a router's path and URL location successfully matches. The match object has some properties but I'll outline the properties you should immediately know about:

  • match.url: returns a string that shows the URL location. Used for s
  • match.path: returns a string that shows the route's path. Used for s
  • match.params: returns an object with values parsed from the URL.

Let's refactor step by step. Refactor the Courses component to have the match object like so:

const Courses = ({ match }) => (
  <div>
     <ul>
        <li><Link to={`${match.url}/technology`}>Technology</Link></li>
        <li><Link to={`${match.url}/business`}>Business</Link></li>
        <li><Link to={`${match.url}/economics`}>Economics</Link></li>
    </ul>

    <Route exact path="/courses/technology" render={() => (<div> This is technology </div>)}/>
    <Route path="/courses/business" component={() => (<div> This is business </div>)}/>
    <Route path="/courses/economics" component={() => (<div> This is economics </div>)}/>
  </div>
);

Test if your URLs are working. Now do the same for the routes but with match.path.

const Courses = ({ match }) => (
  <div>
     <ul>
        <li><Link to={`${match.url}/technology`}>Technology</Link></li>
        <li><Link to={`${match.url}/business`}>Business</Link></li>
        <li><Link to={`${match.url}/economics`}>Economics</Link></li>
    </ul>

    <Route exact path={`${match.path}/technology`} render={() => (<div> This is technology </div>)}/>
    <Route path={`${match.path}/business`} component={() => (<div> This is business </div>)}/>
    <Route path={`${match.path}/economics`} component={() => (<div> This is economics </div>)}/>
  </div>
);

Check your app. Everything should work fine. Now one last step. We can actually replace those three lines of <Route> code with just one line.

const Courses = ({ match }) => (
  <div>
     <ul>
        <li><Link to={`${match.url}/technology`}>Technology</Link></li>
        <li><Link to={`${match.url}/business`}>Business</Link></li>
        <li><Link to={`${match.url}/economics`}>Economics</Link></li>
    </ul>

    <Route exact path={`${match.path}/:course`} render={({match}) => (<div> This is {match.params.course} </div>)}/>
  </div>
);

We used the match.params which provides a key/value object of the URL location. :course is the URL param. Therefore, match.params.course will provide the value of the correct URL location. Awesome!

Route Protection and Authentication

When developing web applications, there are scenarios where certain routes have to be protected from access. Most times, these routes can only be accessed by authorized users.

In previous versions of React Router such as v3, route protection code looks like this:

index.js

const Root = () => {
  return (
    <div className="container">
      <Router history={browserHistory}>
        <Route path="/" component={Display}/>
        <Route path="/upload" component={Upload} onEnter={requireAuth} />
        <Route path="/callback" component={Callback} />
      </Router>
    </div>
  )
}

The <Route/> component had a onEnter prop that accepts a method that allows entry or refusal to a URL location based on a user's authentication status. Now, it's different for React Router 4.

Let's build out three components, Public, Private, and Login.

App.js

import React, { Component } from 'react';
import {
  Route,
  Link,
  BrowserRouter as Router,
} from 'react-router-dom';

const Public = () => (
  <div> This is a public page </div>
);

const Private = () => (
  <div> This is a private page </div>
);

const Login = () => (
  <div> Login Page <button>login</button> </div>
);



class App extends Component {
  render() {
    return (
      <Router>
        <div style={{width: 1000, margin: '0 auto'}}>
          <ul>
            <li><Link to='/public'> Public </Link></li>
            <li><Link to='/private'> Private </Link></li>
          </ul>

          <hr/>

          <Route path='/public' component={Public} />
          <Route path='/private' component={Private} />
        </div>
      </Router>
    );
  }
}
export default App;

Right now, we can access both routes, /public, and /private. Now, let's make sure the /private route can't be accessed until a user is logged in. React Router 4 uses a declarative approach, so it's convenient that we have a component such as <SecretRoute /> that we can use. However, the react router 4 library doesn't provide it. We'll build it. But let's come up with an Auth Service.

In this example, the Auth Service will simply be an object like so:

const AuthService = {
  isAuthenticated: false,
  authenticate(cb) {
    this.isAuthenticated = true
    setTimeout(cb, 100)
  },
  logout(cb) {
    this.isAuthenticated = false
    setTimeout(cb, 100)
  }
}

Now, let's build the <SecretRoute /> like so:

const SecretRoute = ({ component: Component, ...rest }) => (
  <Route {...rest} render={(props) => (
    AuthService.isAuthenticated === true
      ? <Component {...props} />
      : <Redirect to='/login' />
  )} />
);

SecretRoute component

The code above simply illustrates that if the authentication status of the user is true, then a component would be rendered else the user would be redirected to the /login route. Let's try it out.

App.js

import React, { Component } from 'react';
import {
  Route,
  Link,
  Redirect,
  BrowserRouter as Router,
} from 'react-router-dom';

const Login = () => (
  <div> Login Page <button>login</button> </div>
);

const AuthService = {
  isAuthenticated: false,
  authenticate(cb) {
    this.isAuthenticated = true
    setTimeout(cb, 100)
  },
  logout(cb) {
    this.isAuthenticated = false
    setTimeout(cb, 100)
  }
};

const SecretRoute = ({ component: Component, ...rest }) => (
  <Route {...rest} render={(props) => (
    AuthService.isAuthenticated === true
      ? <Component {...props} />
      : <Redirect to='/login' />
  )} />
);

class App extends Component {
  render() {
    return (
      <Router>
        <div style={{width: 1000, margin: '0 auto'}}>
          <ul>
            <li><Link to='/public'> Public </Link></li>
            <li><Link to='/private'> Private </Link></li>
          </ul>

          <hr/>

          <Route path='/public' component={Public} />
          <SecretRoute path='/private' component={Private} />
        </div>
      </Router>
    );
  }
}

export default App;

When you click on the Private link, you are redirected back to /login route. Great! Let's take it a step further by trying to actually log in and log out. Modify the login component like so:

App.js

...
class Login extends React.Component {
  state = {
    redirectToPreviousRoute: false
  };

  login = () => {
    AuthService.authenticate(() => {
      this.setState({ redirectToPreviousRoute: true });
    });
  };

  render() {
    const { from } = this.props.location.state || { from: { pathname: "/" } };
    const { redirectToPreviousRoute } = this.state;

    if (redirectToPreviousRoute) {
      return <Redirect to={from} />;
    }

    return (
      <div>
        <p>You must log in to view the page at {from.pathname}</p>
        <button onClick={this.login}>Log in</button>
      </div>
    );
  }
}

We have modified the Login Component to be able to have a login function and also redirect back to the route that the user was trying to log onto when the user was denied access. This should be typical behavior of your routing system else users will always be redirected to a particular page rather than where they came from!

Now, we'll have to modify the props of the <Redirect /> component in <SecretRoute />.

App.js

const SecretRoute = ({ component: Component, ...rest }) => (
  <Route {...rest} render={(props) => (
    AuthService.isAuthenticated === true
      ? <Component {...props} />
      : <Redirect to={{
          pathname: '/login',
          state: { from: props.location }
        }} />
  )} />
);

We are almost done. However, wouldn't it be nice if we can provide a logout button for the user after successful authentication? Let's create an <AuthStatus /> component.

App.js

...
const AuthStatus = withRouter(({ history }) => (
  AuthService.isAuthenticated ? (
    <p>
      Welcome! <button onClick={() => {
        AuthService.logout(() => history.push('/'))
      }}>Sign out</button>
    </p>
  ) : (
    <p>You are not logged in.</p>
  )
));

In the above code sample, we used withRouter and history.push. withRouter is a higher order component from React Router that allows re-rendering of its component every time the route changes with the same props. history.push is one way of redirecting asides using the <Redirect /> component from React Router.

Now, go ahead and render the <AuthStatus /> component.

App.js

class App extends Component {
  render() {
    return (
      <Router>
        <div style={{width: 1000, margin: '0 auto'}}>
          <AuthStatus />
          <ul>
            <li><Link to='/public'> Public </Link></li>
            <li><Link to='/private'> Private </Link></li>
          </ul>

          <hr/>

          <Route path='/public' component={Public} />
          <Route path="/login" component={Login}/>
          <SecretRoute path='/private' component={Private} />
        </div>
      </Router>
    );
  }
}

Now, try it in the browser again. You should be able to log in and log out successfully!

Link Component Customization

Link Component Customization? What's that? It's simple. You'll learn how to customize your links to have a distinctive look when a particular link is active. React Router 4 has an easy way of accomplishing this task.

Have the code below in your App.js like so:

import React from 'react'
import {
  BrowserRouter as Router,
  Route,
  Link
} from 'react-router-dom'


const Home = () => (
  <div>
    <h2>Home Page</h2>
  </div>
)

const Contact = () => (
  <div>
    <h2>Contact Page</h2>
  </div>
)

class App extends React.Component {
  render() {
    return (
      <Router>
        <div>
            <CustomLink exact={true} to="/">
              Home
            </CustomLink>
            <CustomLink to="/contact">
              Contact
            </CustomLink>

          <hr/>

          <Route exact path="/" component={Home}/>
          <Route path="/contact" component={Contact}/>
        </div>
      </Router>
    )
  }
}

export default App;

The <CustomLink /> is in charge of making the active link distinct. Now, what makes up the<CustomLink /> component? Check out the code below:

const CustomLink = ({ children, to, exact }) => (
  <Route path={to} exact={exact} children={({ match }) => (
    <div className={match ? 'active' : ''}>
      {match ? '> ' : ''}
      <Link to={to}>
        {children}
      </Link>
    </div>
  )}/>
);

It's not complex. The <CustomLink> harnessed the power of <Route>. In the code above, it uses the match object to determine whether to add > symbol whenever the path matches the URL location.

There are 3 ways to render something with a <Route>; <Route component>, <Route render>, and <Route children>. The code above used the children prop. This render prop takes in a function that receives all the same route props as the component and render methods, except when a route doesn't match the URL location. This process gives you the power to dynamically adjust your UI based on whether or not the route matches. And that's all we need to create a custom Link!

Handling Non-existent Routes

As a developer, you need to handle scenarios where certain routes don't exist. If a user stumbles upon your site and visits a non-existent route such as /babalawo. What do you do? Do you just allow your site to break?

This is how to handle this scenario. Add code to your App.js like so:

App.js

import React, { Component } from 'react';
import {
  Route,
  Link,
  Redirect,
  Switch,
  BrowserRouter as Router,
} from 'react-router-dom';

const Home = () => (
  <div>
    <h2>Home Page</h2>
  </div>
)

const Contact = () => (
  <div>
    <h2>Contact Page</h2>
  </div>
)

class App extends Component {
  render() {
    return (
       <Router>
        <div>
          <ul>
            <li>
              <Link to="/">Home</Link>
            </li>
            <li>
              <Link to="/contact">Contact</Link>
            </li>
          </ul>

        <Switch>
          <Route exact path="/" component={Home}/>
          <Route path="/contact" component={Contact}/>
          <Route render={() => (<div> Sorry, this page does not exist. </div>)} />
        </Switch>
        </div>
      </Router>
    );
  }
}

export default App;

In the code above, we imported a new component, <Switch /> from React Router. And we wrapped our routes inside the <Switch /> component. Now, if none of the URLs visited matches the routes defined with a path, then the <Switch /> component invokes the <Route /> with no path and a render function.

Try it out in your browser. Visit a URL that doesn't exist. Your app will display a Sorry, this page does not exist message.

SideBar Rendering

Sidebars in apps have been in existence for a very long time. Let's learn how to make a sidebar using React Router 4. The first step is to throw our routes into an array like so:

import React from 'react'
import {
  BrowserRouter as Router,
  Route,
  Link,
} from 'react-router-dom'

const routes = [
  { path: '/',
    exact: true,
    leftbar: () => <div>Home</div>,
    main: () => <h2>Home</h2>
  },
  { path: '/about',
    leftbar: () => <div>About</div>,
    main: () => <h2>About</h2>
  },
  { path: '/contact',
    leftbar: () => <div>Contact</div>,
    main: () => <h2>Contact</h2>
  }
]

class App extends React.Component {
  render() {
    return (
      <Router>
        <div style={{ display: 'flex' }}>
          <div style={{
            padding: '10px',
            width: '40%',
            background: '#FF6347'
          }}>
            <ul style={{ listStyleType: 'none', padding: 0 }}>
              <li><Link to="/">Home</Link></li>
              <li><Link to="/about">About</Link></li>
              <li><Link to="/contact">Contact</Link></li>
            </ul>

          </div>
        </div>
      </Router>
    )
  }
}

export default App

In the code above, we have a leftbar and a main key. They'll come in handy soon and make our work super easy.

Now, all we need to do is map over the routes array as shown in the code below:

App.js

render() {
  return (
    <Router>
      <div style={{ display: 'flex' }}>
        <div style={{
          padding: '10px',
          width: '40%',
          background: '#FF6347'
        }}>
          <ul style={{ listStyleType: 'none' }}>
            <li><Link to="/">Home</Link></li>
            <li><Link to="/about">About</Link></li>
            <li><Link to="/contact">Contact</Link></li>
          </ul>
          {routes.map((route) => (
            <Route
              key={route.path}
              path={route.path}
              exact={route.exact}
              component={route.leftbar}
            />
          ))}
        </div>

        <div style={{ flex: 1, padding: '20px' }}>
          {routes.map((route) => (
            <Route
              key={route.path}
              path={route.path}
              exact={route.exact}
              component={route.main}
            />
          ))}
        </div>
      </div>
    </Router>
  )
}

In the code above, whenever the route's path matches the URL location, the leftbar component will be rendered. Try it out in your browser and see your left sidebar in action!

Aside: Authenticate a React App with Auth0

We can protect our applications and APIs so that only authenticated users can access them. Let's explore how to do this with a React application using Auth0.

Auth0 login screen

We'll need an Auth0 account to manage authentication. To sign up for a free account, we can follow this link. Next, let's set up an Auth0 application and API so Auth0 can interface with a React App.

Setting Up an Auth0 Application

  1. Let's go to our Auth0 Dashboard and click the "create a new application" button.
  2. Let's call our app as "React Demo" and select "Single Page Web Applications".
  3. In the Settings for our new Auth0 application, let's add http://localhost:3000/callback to the Allowed Callback URLs.
  4. If desired, we can set up some social connections. We can then enable them for our app in the Application options under the Connections tab. The example shown in the screenshot above utilizes username/password database, Facebook, Google, and Twitter. For production, make sure to set up the correct social keys and do not leave social connections set to use Auth0 dev keys.

Set Up an API

  1. Go to APIs in your Auth0 dashboard and click on the "Create API" button. Enter a name for the API. Set the Identifier to your API endpoint URL. In this example, this is http://localhost:3001/api/. The Signing Algorithm should be RS256.
  2. You can consult the Node.js example under the Quick Start tab in your new API's settings. We'll implement our Node API in this fashion, using Express, express-jwt, and jwks-rsa.

We're now ready to implement Auth0 authentication on both our React client and Node backend API.

Dependencies and Setup

There are only two dependencies that we really need to install: auth0.js and history. To do that, let's issue npm install --save auth0-js history in the project root.

Note: As we want the best security available, we are going to rely on the Auth0 login page. This method consists of redirecting users to a login page hosted by Auth0 that is easily customizable right from the Dashboard.

After installing it, we can create an authentication service to interface with the auth0.js script. Let's call this service Auth and create it in the src/Auth/ directory with the following code:

import history from '../history';
import auth0 from 'auth0-js';

export default class Auth {
  auth0 = new auth0.WebAuth({
    // the following three lines MUST be updated
    domain: 'bkrebs.auth0.com',
    audience: 'https://bkrebs.auth0.com/userinfo',
    clientID: '3co4Cdt3h3x8En7Cj0s7Zg5FxhKOjeeK',
    redirectUri: 'http://localhost:3000/callback',
    responseType: 'token',
    scope: 'openid'
  });

  constructor() {
    this.login = this.login.bind(this);
    this.logout = this.logout.bind(this);
    this.handleAuthentication = this.handleAuthentication.bind(this);
    this.isAuthenticated = this.isAuthenticated.bind(this);
  }

  handleAuthentication() {
    this.auth0.parseHash((err, authResult) => {
      if (authResult && authResult.accessToken) {
        this.setSession(authResult);
        history.replace('/home');
      } else if (err) {
        history.replace('/home');
        console.log(err);
      }
    });
  }

  setSession(authResult) {
    // Set the time that the access token will expire at
    let expiresAt = JSON.stringify((authResult.expiresIn * 1000) + new Date().getTime());
    localStorage.setItem('access_token', authResult.accessToken);
    localStorage.setItem('expires_at', expiresAt);
    // navigate to the home route
    history.replace('/home');
  }

  login() {
    this.auth0.authorize();
  }

  logout() {
    // Clear access token and expiration from local storage
    localStorage.removeItem('access_token');
    localStorage.removeItem('expires_at');
    // navigate to the home route
    history.replace('/home');
  }

  isAuthenticated() {
    // Check whether the current time is past the
    // access token's expiry time
    let expiresAt = JSON.parse(localStorage.getItem('expires_at'));
    return new Date().getTime() < expiresAt;
  }
}

The Auth service just created contains functions to deal with various steps of the sign in/sign up process. The following list briefly summarizes these functions and their descriptions:

  • handleAuthentication: looks for the result of the authentication in the URL hash. Then, process the result with the parseHash method from auth0-js;
  • setSession: sets the user's access token and the access token's expiry time;
  • login: initiates the login process, redirecting users to the login page;
  • logout: removes the user's tokens and expiry time from browser storage;
  • isAuthenticated: checks whether the expiry time for the user's access token has passed;

Besides these functions, the class contains a field called auth0 that is initialized with values extracted from the Auth0 application. Let's keep in mind that we need to update them accordingly before proceeding.

Attentive readers probably noticed that the Auth service also imports a module called history that we haven't talked about. We can define this module in only two lines, but let's define it in a file to provide reusability. Let's call this file ./src/history/history.js and add the following code:

import createHistory from 'history/createBrowserHistory'

export default createHistory()

After creating both elements, we can refactor our App component to make use of the Auth service.

import React, { Component } from 'react';
import { Navbar, Button } from 'react-bootstrap';
import './App.css';

class App extends Component {
  goTo(route) {
    this.props.history.replace(`/${route}`)
  }

  login() {
    this.props.auth.login();
  }

  logout() {
    this.props.auth.logout();
  }

  render() {
    const { isAuthenticated } = this.props.auth;

    // ... render the view
  }
}

export default App;

Note that we are passing this service through props. Therefore, when including the App component, we need to inject Auth into it: <App auth={auth} />.

Considering that we are using the Auth0 login page, our users are taken away from the application. However, after they authenticate, users automatically return to the callback URL that we set up previously (http://localhost:3000/callback). This means that we need to create a component responsible for this URL:

import React, { Component } from 'react';
import loading from './loading.svg';

class Callback extends Component {
  render() {
    const style = //...

    return (
      <div style={style}>
        <img src={loading} alt="loading"/>
      </div>
    );
  }
}

export default Callback;

This component can just contain a loading indicator that keeps spinning while the application sets up a client-side session for the users. After the session is set up, we can redirect users to another route.

Please refer to the official Quick Start Guide to see, step by step, how to properly secure a React application. Besides the steps shown in this section, the guide also shows:

Conclusion

Understanding React Router 4 requires a shift in your mental model of routing. I covered the main API concepts for using React Router 4 for the web in this tutorial. However, you can always consult the official documentation for more information.

"Understanding React Router 4 requires a shift in your mental model of routing."