React Router v4 setting activeClass to parent

Not too familiar with the router, but I need NavLink functionality to set the active class in the parent element li , and not in the element a .

To implement this, I simply looked at the source code of NavLink and copied it into a new element. (An example using typescript, but about the same as js)

 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 use:

 <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 use HashRouter and for some reason I can’t understand, it does not update when the route changes, only when I rigidly 'refresh' the page, it updates how it should be.

I believe that it is never updated, because the props never change? So he doesn’t know to update himself?

How can I update this? Or is my problem somewhere else?

+9
reactjs react-router-v4 react-router-dom
source share
3 answers

I am just starting with the reaction, so I’m not sure if these are the best practices, but after going through the documentation for router v4, I used withRouter props → location.pathname and compared it with my route.

Here is Navigation.js:

 import React from 'react'; import { withRouter } from 'react-router-dom'; import NavLink from '../General/NavLink'; const activeClass = (path, link) => { if (path === link) { return true; } return false; }; const Navigation = props => { const { location } = props; return ( <ul className="menu menu--main nano-content"> <NavLink to="/" parentClass={ activeClass(location.pathname, '/') ? 'menu__item menu__item--active' : 'menu__item' } linkClass="menu__link effect effect--waves" > Dashboard </NavLink> <NavLink to="/users" parentClass={ activeClass(location.pathname, '/users') ? 'menu__item menu__item--active' : 'menu__item' } linkClass="menu__link effect effect--waves" > Users </NavLink> <NavLink to="/projects" parentClass={ activeClass(location.pathname, '/projects') ? 'menu__item menu__item--active' : 'menu__item' } linkClass="menu__link effect effect--waves" > Projects </NavLink> <NavLink href="http://google.com" parentClass="menu__item" linkClass="menu__link effect effect--waves" > Google </NavLink> </ul> ); }; export default withRouter(Navigation); 

From there you have parent and child classes that you can use in the child component.

0
source share

In v4, after many attempts, I did.

Here is 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); 

Sandbox demo working code

Working gif image

0
source share

I found that with CSS, you can activate the active link to fill it with the parent <li> element by setting display:block; into the active class.

For example, if our link was:

 <li> <NavLink to="/overview" className=styles.sideLink activeClassName=styles.sideLinkSelected> Overview </NavLink> </li> 

then our CSS will be:

 &__sideLinkSelected { background-color: blue; display:block; } 
-one
source share

All Articles