activeClassName in react router is highlighting two NavLinks at the same time

Viewed 7239

I'm learning React Router and following this tutorial Everything is clear and working as instructed (thank you author) except an issue that highlights the active NavLink.

Take a look at the css file and note the .current class:

nav ul {
  list-style: none;
  display: flex;
  background-color: black;
  margin-bottom: 20px;
}

nav ul li {
  padding: 20px;
}

nav ul li a {
  color: white;
  text-decoration: none;
}

.current {
  border-bottom: 4px solid white;
}

When I load the app, Home link in the navi is highlighted with a the white bottom border line but it stays highlighted even when I click on the "about" link or the "Contact" link. I followed everything step by step but this one issue I can't figure out.

After reading the react documentaton about the NavLink and many tutorials online, still, don't know how to fix it.

Here is when I click on the about link enter image description here

Here is when I click on Contact link enter image description here

This is how the tutorial routes example

<nav>
    <ul>
      <li><NavLink exact activeClassName="current" to='/'>Home</NavLink></li>
      <li><NavLink exact activeClassName="current" to='/about'>About</NavLink></li>
      <li><NavLink exact activeClassName="current" to='/contact'>Contact</NavLink></li>
    </ul>
  </nav>

Notice how the Home link stays with the active white line under it despite the fact that it is not the active link anymore.

Adding activeClassName="current" suppose to highlight the current view with white underline but the home link stays highlighted with the white underline.

So, to all of you out there with years of experience, please help.

Here is My app.js

    import React, { Component } from 'react';
import './App.css';
import Main from './components/main';
import Navigation from './components/navigation';




class App extends Component {
  render() {
    return (
        <div>
            <h1> React Router </h1>;
            <h5>  import 'BrowserRouter' from 'react-router-dom' in Appjs</h5>
            <hr></hr>

            <Navigation />

            <Main />
            </div>

    );
  }
}

 export default App;

Here is my index.js

    import React from 'react';
import ReactDOM from 'react-dom';
//Add browserrouter to use it in your app
import { BrowserRouter } from 'react-router-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';

//this router example is from this site 
//https://blog.pusher.com/getting-started-with-react-router-v4/
/*
You can only pass a single child element to a Router,
so it is necessary to create a root component
that renders the rest of your application and
then pass that in as the child of the Router.
*/
ReactDOM.render((
    <BrowserRouter>
        <App />
    </BrowserRouter>
), document.getElementById('root')); 

Here is my main.js

 import React, { Component } from 'react';
import { NavLink, Switch, Route } from 'react-router-dom';
import Home from './home';
import About from './about'
import Contact from './contact'

class Main extends Component {
    render() {
        return (
            <div>
                <p> My main component </p>
                <Switch>
                    <Route exact={true}  path='/' component={Home}></Route>
                    <Route   path='/about' component={About}></Route>
                    <Route   path='/contact' component={Contact}></Route>
                    </Switch>
            </div>
        );
    }
}

export default Main;

And finally here is my navigation.js

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

class Navigation extends Component {
    render() {
        return (
            <div>
            <p> My Navigation component </p>
            <nav>
                <ul>
                    <li><NavLink to='/'> Home </NavLink> </li>
                    <li><NavLink to='/about'> About </NavLink> </li>
                    <li><NavLink to='/contact'> Contact </NavLink> </li>
                </ul>
            </nav>
                </div>
        );
    }
}

export default Navigation;
6 Answers

The Navlink also needs an exact on it... Change to this:

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

class Navigation extends Component {
  render() {
    return (
      <div>
        <p> My Navigation component </p>
        <nav>
          <ul>
            <li><NavLink to='/' activeClassName="current" exact={true}> Home </NavLink> </li>
            <li><NavLink to='/about' activeClassName="current"> About </NavLink> </li>
            <li><NavLink to='/contact' activeClassName="current"> Contact </NavLink> </li>
          </ul>
        </nav>
      </div>
    );
  }
}

export default Navigation;

You should add the exact property to your root("") Route, otherwise, it will match every route starting with "", React Router exact

eg:

<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/topics" component={Topics} />

Update:

Also changing the order will have same effect without exact property

<Route path="/about" component={About} />
<Route path="/topics" component={Topics} />
<Route path="/" component={Home} />

in side a router switch it will go to the first matching route, if we add a route with path / at the beginning it will always render the component in the path, it is better avoid exact fix with order

for v6, use end instead of exact

<NavLink end activeClassName="activeNavLink" to="/">

Remove activeClassName and activeStyle props from <NavLink />

As of v6.0.0-beta.3, the activeClassName and activeStyle props have been removed from NavLinkProps. Instead, you can pass a function to either style or className that will allow you to customize the inline styling or the class string based on the component's active state.

className

<NavLink
  to="/"
  className={({ isActive }) => "nav-link" + (isActive ? " activated" : "")}
>
  Home
</NavLink>

style

<NavLink
  to="/"
  style={({ isActive }) => ({ color: isActive ? 'green' : 'blue' })}
>
  Home
</NavLink>

source

exact prop has to be provided to the NavLink component.

It works something like this, Home Pictures

When the user clicks on Home, url='/me', it loads home component, when the user clicks on Pictures, url='/me/pictures', if exact is not provided in the NavLink, then both url contains '/me', which makes both of them active.

Its the usecase for exact prop of NavLinks.

You can use exact and strict asper your need in Navlinks.

Related