wobsoriano
wobsoriano

Reputation: 13462

How can I get the correct current path in React using react router 4.2.2's withRouter?

So I have some files:

App.js

class App extends React.Component {

    render() {
        return (
            <div >
                <NavBar />
                <Main />
            </div>
        );
    }

}

export default App;

NavBar.js

class NavBar extends React.Component {

  render() {
    console.log(this.props.match)
    return (
      <div className="navbar-fixed">
        <nav className="light-blue lighten-1">
          <div className="nav-wrapper container">
            <a className="brand-logo">Logo</a>
            <ul id="nav-mobile" className="right hide-on-med-and-down">
              <li><NavLink exact to="/characters" activeClassName="active">Characters</NavLink></li>
              <li><NavLink exact to="/locations" activeClassName="active">Locations</NavLink></li>
            </ul>
          </div>
        </nav>
      </div>
    );
  }
}

export default withRouter(NavBar);

Main.js

class Main extends React.Component {
    render() {
        return (
            <Switch>
                <Route exact path="/characters" component={Characters}/>
                <Route exact path="/locations" component={Locations}/>
            </Switch>
        );
    }
}

export default Main;

The routing works, though in NavBar file, I have the console.log(this.props.match) line and I always get the same path and the activeClassName does not even work.

Whenever I change locations, the output is always:

{
    path: "/", 
    url: "/", 
    params: {…}, 
    isExact: false
}

The only thing that changes is the key isExact.

I can access the pathname now with this.props.location, though I have to make my own login for the active classnames to work.

Am I missing something here?

Upvotes: 1

Views: 1191

Answers (2)

Shubham Khatri
Shubham Khatri

Reputation: 281912

this.props.match gives you the match parameters for the closest matching parent and not the Route in children that is matching, since App is at top level and matches with path='/', printing it in Navbar will always return you

{
    path: "/", 
    url: "/", 
    params: {…}, 
    isExact: false
}

Now say in your case Characters component has a subRoute(note that you should not be using exact keyword if you have nested Routes within it),which you define as

render() {
   return (
      <div>
          {/* other stuff*/}
          <Route path={`${this.props.match.path}/:characterId`} component={Character} />
      </div>
   )
}

In this case even though your url maybe /characters/character-1, console.log(this.props.match) in character component will return you

{
    path: "/character", 
    url: "/character", 
    params: {…}, 
    isExact: false
}

As far as a changing value of isExact is considered, it returns you true of false based on the fact the entire url matches your Route url or not

Upvotes: 1

Evhz
Evhz

Reputation: 9275

Using withRouter appends the location object to the component Properties:

class NavBar extends React.Component {
  // just for reference
  static propTypes = {
    location: PropTypes.object
  }

  render() {
    console.log("Location", this.props.location);
    return (
      <div className="navbar-fixed">
        <nav className="light-blue lighten-1">
          <div className="nav-wrapper container">
            <a className="brand-logo">Logo</a>
            <ul id="nav-mobile" className="right hide-on-med-and-down">
              <li><NavLink exact to="/characters" activeClassName="active">Characters</NavLink></li>
              <li><NavLink exact to="/locations" activeClassName="active">Locations</NavLink></li>
            </ul>
          </div>
        </nav>
      </div>
    );
  }
}

export default withRouter(NavBar);

The props.location has the shape:

{
  key: 'ac3df4',
  pathname: '/somewhere',
  search: '?some=search-string',
  hash: '#howdy',
  state: {
    [userDefined]: true
  }
}

Upvotes: 0

Related Questions