Navbar Component Location Doesn't Update When Route Changed, With React Router
I'm building an app in React and am trying to get the navbar to update when the user navigates to a different page. However it's inconsistent about detecting the change of location prop.
If I go to the Home page and refresh the page, then click the Account link, the Account and Navbar location.pathname prop both change from "/" to "Account", as expected, and the console correctly writes "change".
If I then click the Home link, the Navbar again correctly detects the route change.
However, if I now click "Account" again, the Navbar's location does not update, it remains "/" and the change isn't detected.
I can't see what's different between these two cases, but it consistently works the first time I click "Account" and not the second.
I've read the React Router docs about blocking components, and I don't think that's the problem because the navbar is a top level component, I'm using 'location' as a prop, I'm not using purecomponent, and the Account component does update. And I think if this was the problem, it would never work?
Can anybody suggest how I can get the navbar to consistently detect when the route changes? Thank you!
Navbar.js:
class Navbar extends Component {
constructor(props) {
super(props);
}
componentDidUpdate = (prevProps) => {
console.log('***');
console.log('nav old pathname', prevProps.location.pathname);
console.log('nav new pathname', this.props.location.pathname);
if (prevProps.location.pathname !== this.props.location.pathname) {
// this usually doesn't trigger on navigate
console.log('change');
}
}
render() {
...render my html
}
}
export default connect(mapStateToProps)(withRouter(Navbar));
App.js:
const App = () => (
<Provider store={store}>
<Router>
<div>
<Navbar />
<div className="container">
<Route exact path="/" component={Home} />
<Route exact path="/account" component={Account} />
</div>
</div>
</Router>
</Provider>
);
export default App;
From package.json:
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^1.2.18",
"@fortawesome/free-regular-svg-icons": "^5.8.2",
"@fortawesome/free-solid-svg-icons": "^5.8.2",
"@fortawesome/react-fontawesome": "^0.1.4",
"bootstrap": "^4.2.1",
"classnames": "^2.2.6",
"formik": "^1.5.7",
"i": "^0.3.6",
"jquery": "^3.4.0",
"jwt-decode": "^2.2.0",
"normalizr": "^3.3.0",
"npm": "^6.9.0",
"prop-types": "^15.7.2",
"react": "^16.8.2",
"react-dom": "^16.8.2",
"react-markdown": "^4.0.6",
"react-redux": "^6.0.0",
"react-router-dom": "^4.3.1",
"react-scripts": "3.0.0",
"react-widgets": "^4.4.11",
"reactstrap": "^7.1.0",
"redux": "^4.0.1",
"redux-devtools-extension": "^2.13.8",
"redux-thunk": "^2.3.0",
"reselect": "^4.0.0",
"updeep": "^1.1.0"
},
Answer
The problem is in this line :
export default connect(mapStateToProps)(withRouter(Navbar));
You are not using PureComponent
, but redux connect
is. You can fix this by :
1.Invert the composition :
export default withRouter(connect(mapStateToProps)(Navbar));
2.Pass the location props down in mapStateToProps
:
const mapStateToProps(state, ownProps) {
return {
location: ownProps.location
}
}
Related Questions
- → Import statement and Babel
- → should I choose reactjs+f7 or f7+vue.js?
- → Uncaught TypeError: Cannot read property '__SECRET_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED' of undefined
- → .tsx webpack compile fails: Unexpected token <
- → React-router: Passing props to children
- → ListView.DataSource looping data for React Native
- → React Native with visual studio 2015 IDE
- → Can't test submit handler in React component
- → React + Flux - How to avoid global variable
- → Webpack, React & Babel, not rendering DOM
- → How do I determine if a new ReactJS session and/or Browser session has started?
- → Alt @decorators in React-Native
- → How to dynamically add class to parent div of focused input field?