Craig Wright
Craig Wright

Reputation: 3290

Link, activeClassName just plain not working

I cannot get activeClassName to render correctly in my Navigation component Link. This has been tracked down to the following symptoms:

In the following code, the Navigation component is not getting a props.route passed to it at all. The App component has a props.route, however it is never updated as the user navigates to other routes. It is always set to the first route that was loaded. The componentWillReceiveProps is fired when changing routes, as the props.children is changing.

Here are the relevant snippets of my files:

app.jsx

import router from 'app/router';

[...]

ReactDOM.render(
  <Provider store={store}>
    {router}
  </Provider>,
  document.getElementById('app')
);

router/index.jsx

export default (
  <Router history={browserHistory}>
    <Route path="/" component={App}>
      <IndexRoute component={GameBoard}/>
      <Route path="profile" component={ProfileBoard}/>
      <Route path="profile/:userId" component={ProfileBoard}/>
      <Route path="help" component={Help}/>
      <Route path="about" component={About}/>
    </Route>
  </Router>
);

App.jsx

import React from 'react';
import Navigation from 'Navigation';


export default class App extends React.Component {
  static propTypes = {};

  constructor(props) {
    super(props);
  }

  render() {
    return (
      <div>
        <Navigation />
        <div className="content">
          {this.props.children}
        </div>
      </div>
    );
  }
};

Navigation.jsx

import React from 'react';
import {connect} from 'react-redux';
import {IndexLink, Link} from 'react-router';


export class Navigation extends React.Component {
  static propTypes = {};

  constructor(props) {
    super(props);
  }

  render() {
    return (
      <div className="top-bar navigation">
        <div className="row">
          <div className="small-12 columns">
            <div className="top-bar-left">
              <ul className="menu">
                <li className="menu-text">
                  TVDeadpool.xyz
                </li>
                <li>
                  <IndexLink to="/" activeClassName="link-active">Bets</IndexLink>
                </li>
                <li>
                  <Link to="/help" activeClassName="link-active">Help</Link>
                </li>
                <li>
                  <Link to="/about" activeClassName="link-active">About</Link>
                </li>
              </ul>
            </div>
          </div>
        </div>
      </div>
    );
  }
}

export default connect()(Navigation);

Navigation.jsx has been simplified. I removed some functionality that shows a Logout link if you are logged in, and handles that link. That is the reason I am including connect, though.

I am pouring through the documentation for react-router but cannot for the life of me figure out where I am going wrong. It must be something to do with nesting within the <Provider/>, I guess? Any help would be appreciated!

Note that if you want to see this in (in)action, check out TVDeadpool.xyz. Not a plug, just a fact.

UPDATE

Here is a hack fix:

App.jsx

import React from 'react';
import Navigation from 'Navigation';


export default class App extends React.Component {
  static propTypes = {};

  constructor(props) {
    super(props);
  }

  render() {
    return (
      <div>
        <Navigation location={this.props.location.pathname}/>
        <div className="content">
          {this.props.children}
        </div>
      </div>
    );
  }
};

Simply adding that location prop to <Navigation/> causes a re-render, without any additional code.

I think the reason this is happening is that App is always considered to be at route.path of "/", no matter what route is actually showing. Its immediate children seem to get the appropriate route.path, but Navigation, being a nested component of App, does not. In fact, it does not receive a route prop at all because it is not directly referenced by a <Route/>.

That said, how would this ever work? Should you not be able to simple include Link and expect it to work as described? I feel like I am missing something key to how react-router is supposed to work.

Upvotes: 1

Views: 1358

Answers (1)

codemzy
codemzy

Reputation: 89

I think the reason activeClassName is not working is because you are using connect export default connect()(Navigation);

See this issue... https://github.com/reactjs/react-redux/issues/388

It is reported as fixed in React Router 3.0.0-alpha.1 and newer.

Another hack fix I found you can use in older versions of react router is to pass {pure : false} to tell connect it is not a pure component...

export default connect(mapStateToProps, null, null, { pure: false })(Navigation);

Upvotes: 4

Related Questions