ReactT2_1200x303

Programmatic navigation refers to when a user is redirected as a result of an action that occurs on a route, like a login or signup action. In this article, we'll look at a myriad of approaches to navigating programmatically with React Router.

The React ideology consists of three core concepts: the user event, state management and render function. Programmatic routing can be said to be in line with this ideology.

The effect of routing programmatically is on the same page as no route changing or, at other times, may bring about a need to change a route. When the need arises, it is not going to be triggered by clicking a link, so we don’t always have to use a Link component, and using a Link component in such scenarios is not optimal.

Sometimes we want a different action: We only want to navigate to a different route when a particular event happens or when a user performs an action like submitting a form that leads you to a new page. We refer to this kind of action as programmatic navigation.

React Router is designed to follow the ideology as mentioned earlier. Thus, programmatically navigating with React Router should, by definition, align with those three core concepts.

React Router provides us with a history object, which is accessible by passing this object into each route as a prop. This history object lets us manually control the history of the browser. Since React Router changes what we see based on the current URL, the history object gives us fine-grained control over when or where individual pieces of the application are shown.

What is Programmatic Navigation?

Programmatic Navigation refers to when a user is redirected as a result of an action that occurs on a route. A login or signup action or form submission action on a route is a typical example of navigating programmatically. In this article, we’ll look at a myriad of approaches to navigating programmatically with React Router.

Using Redirect Component

The primary way you programmatically navigate using React Router v4+ is by using a <Redirect /> component, and it’s a recommended method that helps the user navigate between routes.

Using the Redirect component is a different approach but just as valid. The idea is to have it pointing at a state in the component, and if that condition is fulfilled, then navigate.

Some might argue that this method requires more work as one needs to create a new prop on the component’s state and add a condition to the render method to check when to render the Redirect component. This is a fact, but a counter and valid argument, from those who prefer explicit to implicit: It points to the idea that explicitly defining and modifying your state is better as it makes the code more readable against the implicit state handled by an imperative API such as history.push, which we will go over in a bit.

Here’s a code example of how to use the Redirect component.

Codesandbox: https://codesandbox.io/s/gallant-meitner-bshng?file=/src/App.js

import React, { useState } from 'react';
import { Redirect } from 'react-router-dom';
import { userLogin } from './userAction';
import Form from './Form';
const Login = () => {
 const [isLoggedIn, setIsLoggedIn] = useState(false);
  
 const handleLogin = async (userDetail) => {
  const success = await userLogin(userDetail);
  if(success) setIsLoggedIn(true);
 }
  
  if (isLoggedIn) {
   return <Redirect to='/profile' />
  }
  return (
   <>
    <h1>Login</h1>
    <Form onSubmit={handleLogin} />
   </>
  )
}
export default Login;

Using history.push() Method

history.push() is another approach where we make use of the history props React Router provides while rendering a component.

In other words, this works when the component is being rendered by React Router, bypassing the component as a Component prop to a Route. If this is the case, the React Router exposes three props to the component: location, match and history.

We’ll focus on the history prop. The history prop keeps track of all the session history under the hood and provides us with different methods to manipulate it.

The push method is essential and is used to push a path as a route to the history stack, which executes as Last In First Out (LIFO). This causes the app to redirect to the last route added, thereby redirecting the user to a specified route. The example below assumes the component is rendered with React Router.

Codesandbox: https://codesandbox.io/s/angry-saha-djh3z?file=/src/App.js

import React from "react";
import { userLogin } from "./userAction";
import Form from "./Form";
const Login = props => {
 const handleLogin = async userDetail => {
  const success = await userLogin(userDetail);
  if (success) props.history.push("/profile");
 };
 return (
  <>
   <h1>Login</h1>
   <Form onSubmit={handleLogin} />
  </>
 );
};
export default Login;

Using withRouter Method

We mentioned earlier that for a component to have access props.history.push it must have been rendered with React Router. There are cases where this might not be the case. Thus, we render a component ourselves. To make the history property available to the component, the React Router team created the Higher Order Component (HOC) withRouter. Wrapping a component with this HOC exposes the properties as well.

Codesandbox: https://codesandbox.io/s/silent-rain-l19lg?file=/src/App.js:0-442

import React from 'react';
import { withRouter } from 'react-router-dom';
import { userLogin } from './userAction';
import Form from './Form';

const Login = (props) => { 
 const handleLogin = async (userDetail) => {
  const success = await userLogin(userDetail);
  if(success) props.history.push('/profile');
 }
 return (
   <>
    <h1>Login</h1>
    <Form onSubmit={handleLogin} />
   </>
  )
}
export default withRouter(Login);

Using useHistory Hook

As of recent versions of React Router (v5.1) and React (v16.8), we have a new method called the useHistory hook which embraces the power of React Hooks. This is used for programmatic navigation purposes within a functional component. The useHistory hook gives you access to the history instance that we can use to navigate between pages, whether the component has been rendered by React Router or not, and this eliminates the need for using withRouter.

Codesandbox: https://codesandbox.io/s/serene-cookies-hc629?file=/src/App.js

import { useHistory } from "react-router-dom";
const HomeButton = () =>{
 let history = useHistory();
 const handleClick = () => {
  history.push("/home");
 }
 return (
  <button type="button" onClick={handleClick}>
   Go home
  </button>
 );
}
export default HomeButton;

Conclusion

The main focus of this article was to share how you can safely navigate between components using the React Router package.

Considering React has a declarative approach to building UIs, using Redirect is the recommended approach for navigation when the Link cannot be used. There is no harm in using the other methods as they are all supported and semantically correct.

Also, with the introduction of useHistory together other other APIs in the 5.1.2 release, it becomes even easier to navigate programmatically as long as you understand how to use React Hooks.


Gift Egwuenu
About the Author

Gift Egwuenu

Gift Egwuenu is a software developer at Andela and a technical writer based in Lagos, Nigeria. She is passionate about the open source community and enjoys learning new technologies. Learn more about Gift at github.com/lauragift21

Related Posts

Comments

Comments are disabled in preview mode.