React – Routing Parameters, Redirects, & Handling Page Refresh

Photo by mhtoori .com from Pexels

Overview

This post will show examples of setting up routes and passing parameters. Also how to redirect to another route from both a class and function component. In addition to the routing and redirect, there are a couple of strategies for deploying the react application to a server while maintain the ability to refresh the page without getting a 404 error.

Prerequisites

Make sure you have the following library installed. The examples below were written with React Router Dom version 5.2.0.

npm install react-router-dom@5.2.0

Application Router Component

App Router Component

In the file labeled AppRouter.js under “./components/“. This is the router component in app.js. With a layout (app bar and side menu drawer) routes are passed to the content area of the layout to make it responsive.

Also use the exact key word for routes like the root path

<Route exact path="/" component={HomeComp} />  
import React from 'react';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import HomeComp from './../components/Home';
import FunctionComp from './../components/FunctionComponent';
import ClassComp from './../components/ClassComponent';

export default function AppRouter(props) {

  return (
      <div>             
          <Switch>
            <Route exact path="/" component={ListComp} />                        
            <Route path="/class/:id" component={ClassComp} /> 
            <Route path="/product/:id" component={FunctionComp} /> 
          </Switch>               
      </div>
  );
}

App.js

Example below uses router component labeled AppRouter from above inside a <Router> tag. To enable the use for browser Forward and Back buttons to work import createBorwserHistory from “history“;

Code for “./app.js

import React from 'react';
import AppRouter from './components/AppRouter';
import { BrowserRouter as Router} from 'react-router-dom';
import { createBrowserHistory } from "history";

// Enable Browser History for Back and Forward Button
export const appHistory = createBrowserHistory();

function App() {
  return (
    <div>
      <Router history={appHistory}>                                      
        <AppRouter />
      </Router>
    </div>
  );
}

export default App;

Passing Parameters

In order to send the parameter simply add a colon before the parameter name.

Example :id


export default function AppRouter(props) {

  return (
      <div>             
          <Switch>
            <Route exact path="/" component={ListComp} />                        
            <Route path="/class/:id" component={ClassComp} /> 
            <Route path="/product/:id" component={FunctionComp} /> 
          </Switch>               
      </div>
  );
}

The parameter is prefixed with a colon. Example below is a parameter labeled :eventId

path="/class/:eventId"

Function Component – useParams() Hook

You can get the parameters with the useParams() hook. Also added the Link from react-router-dom to go back to the home page.

Example:

import React from 'react'
import { useParams } from "react-router-dom";
import { Link } from 'react-router-dom';

export default function Product(props) {
    let { id } = useParams();

    return (
        <div>
            <Link to="/"> <- Back</Link>
            <br/><br/>
            Product {id}
        </div>
    )
}

Class Component – props

For class components you cannot use the useParams() hook. To get the URL parameter, use the property this.props.match.params.Id.

Example:

import React from 'react'

class ClassComp extends React.Component {

  constructor(props) {
    super(props);
  }
  
  render() {
        
    const id = this.props.match.params.id;                        

    return (
      <React.Fragment>
           Class {id}
      </React.Fragment>
    )
  }
}
export default ClassComp;

There are a lot of variations to this. This is a simple example to pass and receive a URL parameter with the router.

If you just look at the raw data from the URL param in this.props, this is what you will see.
The eventId is under eventId -> match. – > params -> eventId.

Navigation

Navigation with react-router-dom is accomplished with Link. Link Provides declarative, accessible navigation around your application

import { Link } from 'react-router-dom';
...

<Link to={`/product/2`}>Home</Link>
import Button from '@material-ui/core/Button';
import { Link } from 'react-router-dom';
...

<button type="button" component={Link} to={`/product/2`}>Open</button>
import Menu from '@material-ui/core/Menu';
import MenuItem from '@material-ui/core/MenuItem';
import { Link } from 'react-router-dom';

export default function NavMenu() {
  const [anchorEl, setAnchorEl] = React.useState(null);

  const handleClick = (event) => {
    setAnchorEl(event.currentTarget);
  };
  const handleClose = () => {
    setAnchorEl(null);
  };

  return (
  <Menu
     id="simple-menu"
     anchorEl={anchorEl}
     keepMounted
     open={Boolean(anchorEl)}
     onClose={handleClose}>
     <MenuItem onClick={handleClose} component={Link} to="/home">Home</MenuItem>       
     <MenuItem onClick={handleClose}>My account</MenuItem>
     <MenuItem onClick={handleClose}>Logout</MenuItem>
  </Menu>
 )
}

Redirects

In order to navigate to a new location from a component there are a couple of different ways to accomplish this. This depends on the component type. To read more about the React Router Redirects click here or try the examples below for Class and Function Components.

Class Component

Import Redirect from react-router-dom.

import { Redirect } from 'react-router-dom';

Using the JSX tag Redirect under the render() event by changing the state of a boolean variable. In this example redirect is the name of the variable initially set to false.

constructor(props) {
    this.state = { redirect: false }

// ...


hideAlert = (event) => {        
    this.setState({showAlert: false, redirect: true});        
}

// ...

render() {
  if (this.state.redirect) {
     return <Redirect to='/landing'/>;
  }

Function Component

Import useHistory from from react-router-dom.

import { useHistory } from 'react-router-dom';

Then in your function push() the new route.

let history = useHistory();  

onConfirmAlert = event => {
    history.push('/landing');
}

Handling Refresh on the Server

After deploying the building files, there are a couple of ways to mitigate a page refresh error.

LINUX

Update the .htaccess files with the following.

Options -MultiViews
RewriteEngine On 
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.html [QSA,L]

To force a redirect to HTTPS add the following in addition to the above.

# Redirect to HTTPS
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://csjobsearch.com/$1 [R,L]

Windows IIS

If your React app is in a subfolder with the API at the root you can use the API’s web.config and add a custom error for 404.

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.webServer>
    <rewrite>
      <rules>
        <rule name="Static Files" stopProcessing="true">
          <match url="([\S]+[.](html|htm|svg|js|css|png|gif|jpg|jpeg))" />
          <action type="Rewrite" url="/{R:1}"/>
        </rule>
        <rule name="React Router" stopProcessing="true">
          <match url=".*" />
          <conditions logicalGrouping="MatchAll">
            <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
            <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
          </conditions>
          <action type="Rewrite" url="/index.html" />
        </rule>
      </rules>
    </rewrite>
  </system.webServer>
</configuration>

If the React Application is at the root then open the IIS Errors

Update the custom 404 page to redirect to the root and then handle the refresh.