Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Active NavLink to parent element

Tags:

I'm using React Router v4 and I have a case where on my navigation links, I want to enable the active className to the NavLink parent element, not the NavLink itself.

Is there a way to access the path (match) even though I'm not inside the Switch element?

Or do I have to keep state? Because I'm feeling it's kinda missing the idea of router.

Here's my example, I want to apply the active className to li element not NavLink:

const {   HashRouter,   Switch,   Route,   Link,   NavLink, } = ReactRouterDOM  const About = () => (     <article>         My name is Moshe and I'm learning React and React Router v4.     </article> );  const Page = () => (     <Switch>       <Route exact path='/'  render={() => <h1>Welcome!</h1>} />       <Route path='/about' component={About}/>     </Switch> );  const Nav = () => (     <nav>         <ul>             <li><NavLink exact to="/">Home</NavLink></li>             <li><NavLink to="/about">About</NavLink></li>         </ul>     </nav> );  class App extends React.Component {     render() {         return (             <div>                 <Nav />                 <Page />             </div>         );     } } ReactDOM.render((     <HashRouter>         <App />     </HashRouter>),     document.querySelector("#app")); 

https://codepen.io/moshem/pen/ypzmQX

like image 331
Moshe Avatar asked Jan 05 '18 18:01

Moshe


2 Answers

It doesn't seem like it is very easy to achieve. I used withRouter HOC described in react router docs. It gives access to { match, location, history } from props inside components located outside of Routess. In the example I wrapped Nav component to get location and its pathname. Here is the example code:

class Nav extends React.Component {  getNavLinkClass = (path) => {    return this.props.location.pathname === path ? 'active' : '';  }  render() {   return (     <nav>       <ul>         <li className={this.getNavLinkClass("/")}><NavLink exact to="/">Home</NavLink></li>         <li className={this.getNavLinkClass("/about")}><NavLink to="/about">About</NavLink></li>       </ul>     </nav>   )}; } Nav = withRouter(Nav); 

You will probably have to take care of params in your routes (if you have any), to match properly. But you still have to match for each path you have in your NavLink, which might not be pretty code. But the idea is that when the route is changed, Nav is rerendered and correct li is highlighted.

Here is a working example on codesandbox.

like image 107
margaretkru Avatar answered Oct 10 '22 18:10

margaretkru


Can be achived with Route component

<ul>   <Route path="/about">     {({ match }) => <li className={match ? 'active' : undefined}><Link to="/about">About</Link></li>   </Route> </ul> 

Reference: https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/api/Route.md#children-func

like image 36
Piwnik Avatar answered Oct 10 '22 18:10

Piwnik