React Router v4 NavLink active route

I'm trying to port my project from using v3 of react-router to v4 of what is now called react-router-dom. Now the problems arise when I have a MenuBar component, which is completely separate from the routing logic (as you'd expect), because it will show the exact same links whatever the current path may be. Now that worked all nicely with v3, but now when I'm using NavLink, which has the same activeClassName property, the active route does not update on the NavBar, only on refresh. That seems a bit dumb, so there must be a way around this.

export default @inject('ui') @observer class App extends Component {
  render() {
    return (
      <Router>
        <div className={ styles.wrapper }>
          <Sidebar />
          <main className={ `${styles.main} ${!this.props.ui.menuOpen && styles.closed}` }>
            <Route exact path="/" component={ HomePage } />
            <Route path="/signup" component={ SignUpPage } />
            <Route path="/login" component={ LoginPage } />
            <Route path="/about" component={ AboutPage } />
          </main>
          <footer className="site-footer"></footer>
        </div>
      </Router>
    );
  }
}

The above is my main App logic and as you can see the routes are nested, but the Router itself wraps around the whole component.

What should I add to make them work again? (They do work properly on page refresh)

Upvotes: 7

Views: 3314

Answers (1)

Paul S
Paul S

Reputation: 36787

Based on your usage of the @observer decorator, it appears that you are using mobx-react. The thing to understand about observer is that it implements shouldComponentUpdate to optimize rendering performance. That sCU call will look at the current and next props, and if there is no difference, it will not re-render. This is a problem because by default, React Router uses the context to pass data and relies on elements re-rendering to get the updated values, but observer's sCU has no way to detect context changes.

The way that you can get around this is by passing the location object as a prop to the component that is wrapped by observer. Then, when the location changes, observer's shouldComponentUpdate will detect the difference and re-render.

You can see the blocked updates guide for more information.

Upvotes: 4

Related Questions