Little Brain
Little Brain

Reputation: 2837

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"
  },

Upvotes: 1

Views: 2466

Answers (2)

Mohamed Ramrami
Mohamed Ramrami

Reputation: 12691

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
   }
}

Upvotes: 1

jkmosdev
jkmosdev

Reputation: 9

import Switch from react-router-dom to your App.js

import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'

const App = () => (
    <Provider store={store}>
        <Router>
            <div>
                <Navbar />
                <div className="container">
                    <Switch>
                         <Route exact path="/" component={Home} />
                         <Route exact path="/account" component={Account} />
                    </Switch>
                </div>
            </div>
        </Router>
    </Provider>
);

export default App;

don't forget to import Navbar, Home, and Account

Upvotes: 0

Related Questions