Reputation: 2191
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
Reputation: 968
For me what worked has is using NavLink as it has this active class property.
First import it
import { NavLink } from 'react-router-dom';
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>
Style your class in the css by the property active.
.active{
color:#fcfcfc;
}
Upvotes: 1
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
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:
Upvotes: 2
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