user8758206
user8758206

Reputation: 2191

Cannot give class to current link in react

I have some links in a nav menu that outputs html something like this:

<ul>
<li>
<a href="/">Home</a>
</li>
<li>
<a href="/subs">Subs</a>
</li>
</ul>

I'm trying to add a class only to the current page link in the nav menu (e.g. if you're on the / page then the home link should have a class added to it) as per the solution of this post, however, I'm getting the following error:

TypeError: Cannot read property 'route' of undefined

Here is the component:

import React, {Component} from "react";
import {Link} from "react-router-dom";
import {navLinks} from "../util/nav-links";

export default class NavMenu extends React.Component {
  render() {
    var isActive = this.context.router.route.location.pathname === this.props.to;
    var className = isActive ? 'active' : '';

    const lis = navLinks.map(link => (
      <li>
        <Link className={className} to={link.href} key={link.href}>{link.name}</Link>
      </li>
      )
    )

    return (
      <div id="navbar">
        <ul>
          {lis}
        </ul>
      </div>
    )
  }
}

And the /util/nav-links.js file:

export const navLinks = [
  {
    name: "home",
    href: "/"
  },
  {
    name: "subs",
    href: "/subs"
  }
];

Why is this error occuring? If the two variables isActive and className and the className in the link tag are removed then the code works. Also, if there's a better way of achieving this then does anyone have any other methods?

Thanks for any help here. Stackblitz demo: https://stackblitz.com/edit/react-jhedf8?file=src%2Fcomponents%2Fnav-menu.js

Upvotes: 0

Views: 1535

Answers (4)

Fahad Shinwari
Fahad Shinwari

Reputation: 968

For me what worked has is using NavLink as it has this active class property.

  1. First import it

    import { NavLink } from 'react-router-dom';
    
  2. Use an activeClassName to get the active class property.

    <NavLink to="/" activeClassName="active">
      Home
    </NavLink>
    
    <NavLink to="/store" activeClassName="active">
     Store
    </NavLink>
    
    <NavLink to="/about" activeClassName="active">
     About Us
    </NavLink>
    
  3. Style your class in the css by the property active.

    .active{
       color:#fcfcfc;
     }
    

Upvotes: 1

Yousaf
Yousaf

Reputation: 29354

Instead of using Link component, use NavLink component from react-router-dom. NavLink component takes a prop named activeClassName whose value is the class that will be used for the styling to indicate which nav link is active.

<NavLink activeClassName="active" to={link.href} exact>{link.name}</NavLink>

Don't forget to define the class in CSS which you use as a value for activeClassName prop.

For details, see: React Router - NavLink


Not related to the issue but inside the .map() method in NavMenu component, you have added key prop on the Link component but it should be added on the outer li element.

const lis = navLinks.map(link => (
  <li key={link.name}>
    <NavLink activeClassName="active" to={link.href} exact>
      {link.name}
    </NavLink>
  </li>
));

Also note that using NavLink component will remove the need of following two statements in NavMenu component

var isActive = this.context.router.route.location.pathname === this.props.to;
var className = isActive ? 'active' : '';

Upvotes: 1

Maniraj Murugan
Maniraj Murugan

Reputation: 9084

You could modify your code to accept NavLink instead of Link and you can remove all the code related in generating active class that you have inside render method..

Changes as follows:

import {Link} from "react-router-dom";

to:

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

Then,

<Link className={className} to={link.href} key={link.href}>{link.name}</Link>

to:

<NavLink exact activeClassName="active" to={link.href} key={link.href}>{link.name}</NavLink>

nav_menu.js

import React, {Component} from "react";
import { NavLink } from 'react-router-dom';
import {navLinks} from "../util/nav-links";

export default class NavMenu extends React.Component {
  render() {
    const lis = navLinks.map(link => (
      <li>
        <NavLink exact activeClassName="active" to={link.href} key={link.href}>{link.name}</NavLink>
      </li>
      )
    )

    return (
      <div id="navbar">
        <ul>
          {lis}
        </ul>
      </div>
    )
  }
}

style.css:

.
.
.

.active {
   color: #13aa52 !important;
}

Forked Stackblitz:

https://stackblitz.com/edit/react-sxukcd

Upvotes: 2

SSK
SSK

Reputation: 191

2 Options from the link you provided that should work for you:

Option 1 (Answer by Matt):

React-Router V4 comes with a NavLink component out of the box To use, simply set the activeClassName attribute to the class you have appropriately styled, or directly set activeStyle to the styles you want. See the docs for more details.

<NavLink to="/hello" activeClassName="active" >Hello</NavLink>

Option 2 (Answer by ghostkravis):

export default class Navbar extends React.Component {
render(){
const { location } = this.props;

const homeClass = location.pathname === "/" ? "active" : "";
const aboutClass = location.pathname.match(/^\/about/) ? "active" : "";
const contactClass = location.pathname.match(/^\/contact/) ? "active" : "";


return (
<div>
      <ul className="nav navbar-nav navbar-right">
        <li className={homeClass}><Link to="/">Home</Link></li>
        <li className={aboutClass}><Link to="about" activeClassName="active">About</Link></li>
        <li className={contactClass}><Link to="contact" activeClassName="active">Contact</Link></li>
      </ul>

</div>
    );}}

Upvotes: 2

Related Questions