Not too familiar with react router, but I need the functionality of the NavLink to set the active class on the parent li
element, and not the a
element.
To implement this I just looked at the source code of the NavLink
and copied it to a new element. (Example using typescript, but just about the same as js anyway)
import * as React from 'react';
import { Link, withRouter, Route } from 'react-router-dom';
class LiNavLink extends React.Component<any, {}> {
render() {
const {to,exact, strict, activeClassName, className, activeStyle, style, isActive: getIsActive, ...rest } = this.props;
return (
<Route
path={typeof to === 'object' ? to.pathname : to}
exact={exact}
strict={strict}
children={({ location, match }) => {
const isActive = !!(getIsActive ? getIsActive(match, location) : match)
return (
<li
className={isActive ? [activeClassName, className].join(' ') : className}
style={isActive ? { ...style, ...activeStyle } : style}>
<Link
to={to}
{...rest}
/>
</li>
)
}}
/>
);
}
}
export default LiNavLink;
Then the usage:
<ul>
<LiNavLink activeClassName='active' exact={true} strict to="/example"><span>Active</span></LiNavLink>
<LiNavLink activeClassName='active' exact={true} strict to="/example/archived"><span>Archived</span></LiNavLink>
</ul>
I'm using a HashRouter
and for some reason which I can't figure out, this does not update when the route changes, only when I hard 'refresh' the page does it update how it should.
I believe it is never updating because the props never change? So it doesn't know to update itself?
How can I get this to update? Or is my problem somewhere else?
In v4 after lots of tries I did.
Here my working code.
import React, { Component } from "react";
import logo from "../../logo.svg";
import { Link, withRouter } from "react-router-dom";
import PropTypes from "prop-types";
class Navbar extends Component {
static propTypes = {
match: PropTypes.object.isRequired,
location: PropTypes.object.isRequired,
history: PropTypes.object.isRequired
};
state = {};
getNavLinkClass = path => {
return this.props.location.pathname === path
? "nav-item active"
: "nav-item";
};
render() {
return (
<nav className="navbar navbar-expand-lg navbar-dark bg-dark">
<Link className="navbar-brand" to="/">
<img
src={logo}
width="30"
height="30"
className="d-inline-block align-top"
alt=""
/>
Utility
</Link>
<button
className="navbar-toggler"
type="button"
data-toggle="collapse"
data-target="#navbarNav"
aria-controls="navbarNav"
aria-expanded="false"
aria-label="Toggle navigation"
>
<span className="navbar-toggler-icon" />
</button>
<div className="collapse navbar-collapse" id="navbarNav">
<ul className="navbar-nav">
<li className={this.getNavLinkClass("/")}>
<Link className="nav-link" to="/">
Home
</Link>
</li>
<li className={this.getNavLinkClass("/age-counter")}>
<Link className="nav-link" to="/age-counter">
Age Counter
</Link>
</li>
</ul>
</div>
</nav>
);
}
}
export default withRouter(Navbar);
Demo working Code Sandbox