Search code examples
javascriptreactjstwitter-bootstrapreact-bootstrap

Refresh page to update link active status based on window.location.pathname


I'm starting to learn ReactJS and I have created a small app with 3 screens: home, about & users. I am using bootstrap for styles.

I have the following logic active={window.location.pathname === "/about"} for each link to pass in a boolean to determine if it the active page or not.

When I click the links it loads the page I need however the style doesn't update to reflect that the link is active however if I refresh the page it updates the style.

From what I've read online I can do something with states to reload the page to update the style etc but I'm not sure how to actually implement this.

Any help would be greatly appreciated.

App.js

import React, { Component } from 'react';

import {
  BrowserRouter as Router,
  Switch,
  Route
} from "react-router-dom";

import './App.css';

import Navigation from './components/navigation';

import Home from './views/home';
import Users from './views/users';
import About from './views/about';

export default class App extends Component {
  render(){
    return (
      <div className="App">
        <Router>
          <Navigation></Navigation>
          <Switch>
            <Route path="/about"><About /></Route>
            <Route path="/users"><Users /></Route>
            <Route path="/"><Home /></Route>
          </Switch>
        </Router>
      </div>
    );
  }
}

Navigation.js

import React, { Component, useState } from 'react';

import NavigationItem from './navigationItem';

export default class Navigation extends Component {

    render(){
        return( 
            <div>
                <nav class="navbar navbar-expand-lg navbar-light bg-light">
                    <div class="container-fluid">
                        <a class="navbar-brand" href="#">Navbar</a>
                        <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
                            <span class="navbar-toggler-icon"></span>
                        </button>
                        <div class="collapse navbar-collapse" id="navbarSupportedContent">
                            <ul class="navbar-nav me-auto mb-2 mb-lg-0">
                                <NavigationItem active={window.location.pathname === "/"} path="/" content="Home"></NavigationItem>
                                <NavigationItem active={window.location.pathname === "/about"} path="/about" content="About"></NavigationItem>
                                <NavigationItem active={window.location.pathname === "/users"} path="/users" content="Users"></NavigationItem>    
                            </ul>
                        </div>
                    </div>
                </nav>
            </div>     
        );
    }
}

NavigationItem.js

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

export default class NavigationItem extends Component {
    render(){
        if(this.props.active){
            return(
                <li class="nav-item">
                    <Link class="nav-link active" to={this.props.path}>{this.props.content}</Link>
                </li> 
            );
        } else {
            return(
                <li class="nav-item">
                    <Link class="nav-link" to={this.props.path}>{this.props.content}</Link>
                </li> 
            );
        }
    }
}

Solution

  • There's another React Router component called NavLink that has an activeClassName attribute that you may find useful.

    I use it like this:

    <li>
      <NavLink
        activeClassName={styles.active}
        to="/path"
      >Route path
      </NavLink>
    </li>
    

    where active is the class I bring in from my CSS module.