Reputation: 2843
I have seen multiple questions related to this and I have tried them all, with no results. So, posting yet another seemingly duplicate question.
I am trying to highlight the current page button in the navigation bar. For simple examples, where I am not routing it to a new page, it works. But when I route it to a different page (a separate react component) it doesn't work.
Here is the code I have:
App.jsx:
class App extends Component {
render() {
return (
<BrowserRouter>
<div>
<Route exact={true} path='/' component={HomeApp}/>
<Route path='/form' component={SomeForm}/>
</div>
</BrowserRouter>
);
}
}
NavigationBar.jsx
class NavigationBar extends Component {
componentDidMount() {
toggleIcon();
}
render() {
return (<div id="topheader">
<nav className="navbar navbar-expand-lg navbar-light bg-light ">
<a className="navbar-brand" href="#">Whatever</a>
<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"></span>
</button>
<div className="collapse navbar-collapse" id="navbarNav">
<ul className="navbar-nav nav nav-pills ml-auto">
<li className="nav-item active">
<a className="nav-link" href="/">Home <span className="sr-only">(current)</span></a>
</li>
<li className="nav-item">
<a className="nav-link" href="/form">Submit Form</a>
</li>
<li className="nav-item">
<a className="nav-link" href="#">Sign Up</a>
</li>
<li className="nav-item">
<a className="nav-link " href="#">Login</a>
</li>
</ul>
</div>
</nav>
</div>
)
}
}
export default NavigationBar
navigation.js
import $ from 'jquery';
export function toggleIcon() {
$( '#topheader .navbar-nav a' ).on( 'click', function () {
$( '#topheader .navbar-nav' ).find( 'li.active' ).removeClass( 'active' );
$( this ).parent( 'li' ).addClass( 'active' );
});
}
As seen, the highlighting works when I click Sign Up
or Login
, as they are not being routed to any other component.
But when I click on Submit Form
which is routed to SomeForm
component, the highlighting goes back to Home
button.
For more details, I am posting the contents of HomeApp
and SomeForm
components:
HomeApp.jsx
class HomeApp extends Component {
render() {
return (
<div className="container">
<NavigationBar/>
<Jumbotron/>
</div>
)
}
}
export default HomeApp
SomeForm.jsx
class SomeForm extends Component {
render() {
return (<>
<div className="container">
<NavigationBar>
</NavigationBar>
</div>
</>
)
}
}
export default SomeForm
Upvotes: 1
Views: 6873
Reputation: 111
Since you need to highlight parent element of link (li) you can use withRouter (or useLocation hook for functional components) with NavLink from react-router in NavigationBar:
import React, { Component } from 'react';
import { withRouter } from 'react-router';
class NavigationBar extends Component {
constructor(props) {
super(props);
this.renderMenuLink = this.renderMenuLink.bind(this);
}
componentDidMount() {
toggleIcon();
}
renderMenuLink({ path, label }) {
const { location } = this.props;
const isActive = location.pathname === path;
return (
<li key={path} className={`nav-item ${isActive ? 'active' : ''}`}>
<NavLink className="nav-link" to={path}>
{label}{isActive ? <span className="sr-only">(current)</span> : ''}
</NavLink>
</li>
);
}
render() {
const menuLinks = [
{ path: '/', label: 'Home' },
{ path: '/form', label: 'Submit Form' },
{ path: '/register', label: 'Sign Up' },
{ path: '/login', label: 'Login' },
];
return (<div id="topheader">
<nav className="navbar navbar-expand-lg navbar-light bg-light ">
<a className="navbar-brand" href="#">Whatever</a>
<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"></span>
</button>
<div className="collapse navbar-collapse" id="navbarNav">
<ul className="navbar-nav nav nav-pills ml-auto">
{menuLinks.map((menuLink) => this.renderMenuLink(menuLink))}
</ul>
</div>
</nav>
</div>
)
}
}
export default withRouter(NavigationBar);
Upvotes: 1
Reputation: 4536
Please follow along this structure:
import { BrowserRouter, Switch, Route } from "react-router-dom"
class App extends React.Component{
render() {
return (
<BrowserRouter>
<div className="App">
<Navigation />
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/about" component={About} />
<Route exact path="/contact" component={MoreRoutes} />
</Switch>
</div>
</BrowserRouter>
)
}
}
And you need to use NavLink as @Mikail Bayram mentioned, that will allow you to use activeClassName also, the exact
prop is required on each of your routes to have routes render only when the path is have the exact match. Please note that you can call the active
class whatever you like.
Your Navigation should look like this:
import { NavLink } from "react-router-dom"
const Navigation = () => (
<nav>
<ul>
<li>
<NavLink exact activeClassName="active" to="/">
Home
</NavLink>
</li>
<li>
<NavLink exact activeClassName="active" to="/about">
About
</NavLink>
</li>
<li>
<NavLink exact activeClassName="active" to="/contact">
Contact
</NavLink>
</li>
</ul>
</nav>
)
As a side note: You should Never combining jQuery with React
Here is a live example at codeSandbox
Upvotes: 4