technogeek1995
technogeek1995

Reputation: 3454

React Router (v4) Navbar

I am using v4 of react-router-dom

I need to access this.props.match in my nav bar component so I can set the active class. I'm using react-materialize. In the <NavItem> tag, I want to add className={this.props.match ? 'active' : ''}. However, I can't seem to access the match. Props is an empty object every time when I print it in the console.

My Nav.js

<Navbar brand='Fuzic' href="/" className="orange darken-3" right>
  <NavItem className={this.match ? 'active' : ''} href="/devices">Devices</NavItem>
  <NavItem><Link to="/devices">Media</Link></NavItem>
  <NavItem><Link to="/devices">Alarms</Link></NavItem>
  <NavItem><Link to="/devices">Interrupts</Link></NavItem>
  <NavItem><Link to="/auth">Admin</Link></NavItem>
</Navbar>

My App.js

<BrowserRouter>
  <div>
    <Nav/>
    <div className="container">
      <Switch>
        <PropsRoute exact path="/" component={Auth}/>
        <PropsRoute exact path="/devices" component={Devices} devices={this.state.devices} setCurrentDevice={this.setCurrentDevice} />
        <PropsRoute path="/devices/:deviceId" component={Detail} currentDevice={this.state.currentDevice} />
        <PropsRoute path="/auth" component={Auth}/>
        <PropsRoute component={NotFound}/>
      </Switch>
    </div>
  </div> 
</BrowserRouter>

helper.js - combines props passed by me & props passed from react-router

// Exerp From:  https://github.com/ReactTraining/react-router/issues/4105
export const renderMergedProps = (component, ...rest) => {
  const finalProps = Object.assign({}, ...rest);
  return (
    React.createElement(component, finalProps)
  );
}

export const PropsRoute = ({ component, ...rest }) => {
  return (
    <Route {...rest} render={routeProps => {
      return renderMergedProps(component, routeProps, rest);
    }}/>
  );
}

Most of the documentation and articles online are for v2&3. The docs for v4 don't go into detail on how to handle this. Many people nested a route for their app. However, when I do that, I get a stack overflow in the console with a print of the frames.

How do I fix this so I can get access to match?

Upvotes: 10

Views: 6554

Answers (4)

Devgig
Devgig

Reputation: 183

"react": "^16.9.0" and "reactstrap": "^8.0.1"

import { NavLink} from "react-router-dom";
import { NavbarBrand} from "reactstrap";

 <NavLink 
  className="navbar-brand"
  activeClassName="active"
  tag={NavbarBrand}
  to='/'
  >
  My App
  </NavLink>

Upvotes: 1

Alexey
Alexey

Reputation: 2164

For those who are working with react-bootstrap v4 (using 1.0.0-beta.5 currently) and react-router-dom v4 (4.3.1) just use "as" prop from Nav.Link, here is full example:

import { Link, NavLink } from 'react-router-dom'
import { Navbar, Nav } from 'react-bootstrap'

<Navbar>
  {/* "Link" in brand component since just redirect is needed */}
  <Navbar.Brand as={Link} to='/'>Brand link</Navbar.Brand>
  <Nav>
    {/* "NavLink" here since "active" class styling is needed */}
    <Nav.Link as={NavLink} to='/' exact>Home</Nav.Link>
    <Nav.Link as={NavLink} to='/another'>Another</Nav.Link>
    <Nav.Link as={NavLink} to='/onemore'>One More</Nav.Link>
  </Nav>
</Navbar>

Here is working example: https://codesandbox.io/s/3qm35w97kq

Upvotes: 2

gkri
gkri

Reputation: 2003

This is how I implement it, it works with
"react-router-dom": "^4.2.2"
"react-bootstrap": "^0.31.5"

import { Link } from 'react-router-dom';
import { NavBar, Nav, NavItem} from 'react-bootstrap';

const NavBar = ({location}) => (
    <NavBar>
        <Nav>
            <NavItem componentClass={Link} href="/artists" to="/artists" active={location.pathname === '/artists'}>Artists</NavItem>
            <NavItem componentClass={Link} href="/stages" to="/stages" active={location.pathname === '/stages'}>Stages</NavItem>
        </Nav>
    <NavBar>
// ...

Where location is the native property of a Route: https://reacttraining.com/react-router/web/api/location

Hope this helps.

EDIT: Just noticed that you're using react-materialize so my answer is probably not applicable to your question.

Upvotes: 1

Seyhan
Seyhan

Reputation: 632

On your Nav component, try using react router's <NavLink> instead of <Link>.

<NavLink> is a special version of the <Link> that will add styling attributes to the rendered element when it matches the current URL.

<NavLink> has activeClassName and activeStyle properties that you can use them to apply style to your active navigation item.

For example a basic navigation would be like this:

<nav>
    <NavLink activeStyle={{color: 'red'}} to="/foo">Foo</NavLink>
    <NavLink activeStyle={{color: 'red'}} to="/bar">Bar Group</NavLink>
    <NavLink activeStyle={{color: 'red'}} to="/another-foo">Another Foo</NavLink>
    <NavLink activeStyle={{color: 'red'}} to="/another-bar">Another Bar</NavLink>
</nav>

Where activeStyle represents the style to apply to the element when it is active.

And below the same example via activeClassName:

<nav>
    <NavLink activeClassName="selected" to="/foo">Foo</NavLink>
    <NavLink activeClassName="selected" to="/bar">Bar Group</NavLink>
    <NavLink activeClassName="selected" to="/another-foo">Another Foo</NavLink>
    <NavLink activeClassName="selected" to="/another-bar">Another Bar</NavLink>
</nav>

activeClassName is the class to give the element when it is active. For this example I choose it to be selected. By default in react-router v4 given class for the active state is active.

Find more about <NavLink> on react-router v4 documentation

Upvotes: 6

Related Questions