React-router: Redux connected component doesn't rerender when location changes

Created on 6 Apr 2017  路  3Comments  路  Source: ReactTraining/react-router

Version

react-router-dom: 4.0.0

Steps to reproduce

$ create-react-app
$ cd app
$ yarn add redux react-router-dom react-redux

which produces:

{
  "name": "app",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "react": "^15.4.2",
    "react-dom": "^15.4.2",
    "react-redux": "^5.0.3",
    "react-router-dom": "^4.0.0",
    "redux": "^3.6.0"
  },
  "devDependencies": {
    "react-scripts": "0.9.5"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  }
}

Then

// src/index.js

import React    from 'react'
import ReactDOM from 'react-dom'
import App      from './App'

const MOUNT_NODE = document.getElementById('root')

import { Provider } from 'react-redux'
import { BrowserRouter as Router } from 'react-router-dom'
import { createStore } from 'redux'

// dummy reducer
function dummy() {
  return {}
}

const store = createStore(dummy)

ReactDOM.render((
  <Provider store={store}>
    <Router>
      <App/>
    </Router>
  </Provider>
), MOUNT_NODE)
// src/App.js

import React from 'react'
import { Link, Route } from 'react-router-dom'
import { connect } from 'react-redux'

function App() {
  return (
    <div className="app">
      <ul>
        <li><Link to="/">Home</Link></li>
        <li><Link to="/profile">Profile</Link></li>
      </ul>
      <div className="routes">
        <Route path="/" render={() => (
          <h1>Home</h1>
        )}/>
        <Route path="/profile" render={() => (
          <h1>Profile</h1>
        )} />
      </div>
    </div>
  )
}

export default connect()(App)

Expected Behavior

Render <h1>Profile</h1> without reload when <Link to="/profile">Profile</Link> clicked.

Actual Behavior

Doesn't re-render except this line:

export default connect()(App)

changed to

export default App

Most helpful comment

It's also possible to wrap your AppComponent in withRouter decorator:

- export default connect()(App)
+ export default withRouter(connect()(App))

Not sure about performance consequences, though.

All 3 comments

I've found that if you have the NODE_ENV variable set to production, the connect will block component updates. But when I ran in development mode, routes changed normally.

I fixed it by writing a very simple wrapper:

+class HistoryPusher extends React.Component {
 +  static propTypes = {
 +    location: React.PropTypes.object
 +  }
 +
 +  static defaultProps = {
 +    location: {}
 +  }
 +
 +  componentWillReceiveProps(nextProps) {
 +    if (!this.props.location || !nextProps.location) {
 +      return
 +    }
 +    if (this.props.location.pathname !== nextProps.location.pathname) {
 +      store.dispatch(setLocation(location))
 +    }
 +  }
 +
 +  render() {
 +    return this.props.children
 +  }
 +}
 +
 +const HistoryPusherWithRouter = withRouter(HistoryPusher)
 +
  const rootEl = document.getElementById('content')
  const wrapApp = AppComponent =>
    (<Provider store={store} key="provider">
      <BrowserRouter>
 -      <AppContainer>
 -        <AppComponent store={store} client={client} />
 -      </AppContainer>
 +      <HistoryPusherWithRouter>
 +        <AppContainer>
 +          <AppComponent store={store} client={client} />
 +        </AppContainer>
 +      </HistoryPusherWithRouter>
      </BrowserRouter>
    </Provider>)

And then adding a location path in my redux store and connecting that path to my App component:

@connect(
    state => ({
      user: state.auth.user,
 +    location: state.location,
    }), { logout })
  export default class App extends Component {
    static propTypes = {

It's also possible to wrap your AppComponent in withRouter decorator:

- export default connect()(App)
+ export default withRouter(connect()(App))

Not sure about performance consequences, though.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

yormi picture yormi  路  3Comments

jzimmek picture jzimmek  路  3Comments

alexyaseen picture alexyaseen  路  3Comments

winkler1 picture winkler1  路  3Comments

ArthurRougier picture ArthurRougier  路  3Comments