Components not re-rendering on route change - React HashRouter

react-router programmatically change route
react-router unmount component on route change
component does not remount when route parameters change
usehistory hook
browserrouter
react router not rendering component
react router state
react router props

I've got a problem with react and react-router. When I click on a link (in my example contact in Footer.js), the url changes, but the desired component Location is not shown. When I refresh the site then, the correct component is displayed.

App.js:

import React, { Component } from 'react';
import { BrowserRouter as Router, HashRouter, Route, Link } from 'react-router-dom';
import 'bootstrap/dist/css/bootstrap.css';
import Footer from './Footer.js';
import Navigation from './Navigation.js';
import Background from './Background.js';
import Home from './Home.js';
import Products from './Products.js';
import Industries from './Industries.js';
import Partner from './Partner.js';
import Location from './Location.js';
import MeetUs from './MeetUs.js';
import ScrollUp from './ScrollUp.js';
import Divider from './Divider.js';
import Country from './Country.js';
import Language from './Language.js';
import Waypoint from 'react-waypoint';
import $ from "jquery";

class App extends Component {

  constructor(props) {
    super(props);
    this.state = {
      currentLanguage: 'en',
      currentBU: '',
      currentIndustry: '',
      showMainProductGroups: false,
      currentCountry: 'group',
      countryObject: Country['group'],
      contacts: [],
      mainProductGroups: [],
    };
  }

  handleCountryChange() {
  //...
  }

  handleLanguageChange() {
  //...
  }

  handleBUChange() {
  //...
  }

  render() {
    const routes = [
      { 
        path: '/',
        exact: true,
        components: () => 
          <div>
            <Home key="home" currentLanguage={this.state.currentLanguage} />
          </div>,
      },
      { 
        path: '/contact',
        exact: true,
        components: () => <Location key="locations" currentLanguage={this.state.currentLanguage} country={this.state.countryObject} contacts= {this.state.contacts} onCountryChange={this.handleCountryChange.bind(this)} />
      },
    ]
    return (
      <HashRouter>
    <div>
      <Background />
      <div id="wrap">
        <div id="main" className="container clear-top marginBottom50px">
            <div id="content">
              <Navigation key="navBar" currentLanguage={this.state.currentLanguage} onLanguageChange={this.handleLanguageChange.bind(this)} onBUChange={this.handleBUChange.bind(this)} onCountryChange={this.handleCountryChange.bind(this)} />
              {
                routes.map((route, index) => (
                <Route key={index} path={route.path} exact={route.exact} component={route.components} />
              ))
              }
            </div>
        </div>
      </div>
      <Footer key="footer" currentLanguage={this.state.currentLanguage} />
      <ScrollUp key="scrollUp" />
    </div>
  </HashRouter>
    );
  }
}

export default App;

Home.js:

import React, { Component } from 'react';
import $ from "jquery";
import {  Link } from 'react-router-dom';
import {withRouter} from 'react-router';
import Language from './Language.js';
import locations from './locations.jpg';
import locationLegend from './locationLegend.jpg';
require('bootstrap')

class Home extends Component {
    constructor(props) {
        super(props);
        this.state = {
        };
    }

    render() {
        return (
            <div className="container marginTop50px marginBottom50px area">
                <div className="row">
                    <div className="col-12 text-center animDelay2 fadeInDown animated">
                        <h1>International Distribution of Specialty Chemicals</h1>
                    </div>
                </div>
                <div className="row marginTop25px">
                    <div className="col-12 text-center animDelay2 fadeInUp animated">
                        {Language[this.props.currentLanguage].homeStartText}
                    </div>
                </div>
                <div className="row marginTop25px">
                    <div className="col-12 text-center">
                        <img src={locations} className="img-fluid" alt="Locations" />
                    </div>
                </div>
                <div className="row marginTop25px">
                    <div className="col-12 text-center">
                        <img src={locationLegend} className="img-fluid" alt="Locations" />
                    </div>
                </div>
            </div>
        );
    }
}

export default withRouter(Home);

Location.js:

import React, { Component } from 'react';
import $ from "jquery";
import { Link } from 'react-router-dom';
import Language from './Language.js';
import Country from './Country.js';
import ContactPerson from './ContactPerson.js';
import locations from './locations.png';
import phone from './phoneBlack.svg';
import fax from './faxBlack.svg';
import email from './emailBlack.svg';
import {withRouter} from 'react-router';
require('bootstrap');

class Location extends Component {
    constructor(props) {
        super(props);
        this.state = {
        };
    }

    componentDidUpdate(prevProps, prevState, snapshot) {
        console.log('Country change:' + this.props.country.key);
        $('#selectCountry').val(this.props.country.key); //name['en']
    }

    onCountryChange() {
        let countryName = this.refs.country.value;
        this.props.onCountryChange(countryName);
    }

    render() {
        return (
            <div className="container marginTop50px marginBottom50px area" id="locations">
                <div className="row">
                    <div className="col-12 text-center">
                        <h2>{Language[this.props.currentLanguage].locations}</h2>
                    </div>
                </div>
                <div className="row marginTop25px">
                    <div className="col-12 text-center">
                        <div className="form-group">
                            <select id="selectCountry" className="form-control" ref="country" onChange={this.onCountryChange.bind(this)}>
                                <option defaultValue>{Language[this.props.currentLanguage].selectLocation.toUpperCase()}</option>
                                {
                                    Object.keys(Country).map((countryKey) => {
                                        const country = Country[countryKey];
                                        return (
                                            <option value={countryKey} key={"loc" + countryKey}>{country.name[this.props.currentLanguage].toUpperCase()}</option>
                                        );
                                    })
                                }
                            </select>
                        </div>
                    </div>
                </div>
                <div className="row marginTop25px">
                    <div className="col-12 text-center">
                        {this.props.country.name[this.props.currentLanguage].toUpperCase()}
                        <br />
                        <address>
                            <span dangerouslySetInnerHTML={{__html: this.props.country.address}}></span>
                            <br />
                            <br />
                            <img src={phone} alt="Anrufen" className="phoneMain"></img><span> </span>
                            <a href={this.props.country.phoneHTML}>{this.props.country.phone}</a>
                            <br />
                            <img src={fax} alt="Fax" className="phoneMain"></img><span> </span>
                            <a href={this.props.country.faxHTML}>{this.props.country.fax}</a>
                            <br />
                            <img src={email} alt="Email" className="emailMain"></img><span> </span>
                            <a href={"mailto://" + this.props.country.email}>{this.props.country.email}</a>
                        </address>
                    </div>
                </div>
                <div className="row marginTop25px">
                    <div className="col-12 text-center">
                        {Language[this.props.currentLanguage].vatRegistrationNumber + ": " + this.props.country.vatNo}
                        <br />
                        {Language[this.props.currentLanguage].registrationOffice + ": "}
                        <span dangerouslySetInnerHTML={{__html: this.props.country.registrationOffice}}></span>
                    </div>
                </div>
                <div className="row marginTop50px">
                    <div className="col-12 text-center">
                        <h3>{Language[this.props.currentLanguage].contact}</h3>
                    </div>
                </div>
                <div className="row">

                        {
                            this.props.contacts.map((contact) => {
                                return (
                                    <div className="col-12 col-sm-12 col-md-12 col-lg-6 text-center">
                                        <ContactPerson contact={contact} key={"contact" + contact.id} />
                                    </div>
                                );
                            })
                        }
                </div>
            </div>
        );
    }
}

export default withRouter(Location);

Footer.js:

import React, { Component } from 'react';
import $ from "jquery";
import {  Link } from 'react-router-dom';
import {withRouter} from 'react-router';
import Language from './Language.js';
import phone from './phoneWhite.svg';
import fax from './faxWhite.svg';
require('bootstrap');

class Footer extends Component {
    constructor(props) {
        super(props);
        this.state = {
        };
    }

    render() {
        return (
            <footer className="footer">
                <div className="container-fluid borderTop1px footerLayout">
                    <div className="row">
                        <div className="col-3">
                            <address>
                                <small>
                                    Some text
                                </small>
                            </address>
                        </div>
                        <div className="col-6 text-center">
                            <div className="row">
                                <div className="col-12 col-sm-12 col-md-12 col-lg-3 text-center">
                                    <a href="https://download.group.com" className="nav-link footerLink" target="_self"><small>{Language[this.props.currentLanguage].download}</small></a>
                                </div>
                                <div className="col-12 col-sm-12 col-md-12 col-lg-3 text-center">
                                    <Link to="/imprint" className="nav-link footerLink"><small>{Language[this.props.currentLanguage].imprint}</small></Link>
                                </div>
                                <div className="col-12 col-sm-12 col-md-12 col-lg-3 text-center">
                                    <Link to="/contact" className="nav-link footerLink"><small>{Language[this.props.currentLanguage].contact}</small></Link>
                                </div>
                                <div className="col-12 col-sm-12 col-md-12 col-lg-3 text-center">
                                    <Link to="/termsAndConditions" className="nav-link footerLink"><small>{Language[this.props.currentLanguage].termsAndConditions}</small></Link>
                                </div>
                            </div>
                        </div>
                        <div className="col-3">
                            <ul className="list-inline">
                                <li>
                                    <img src={phone} alt="Anrufen" className="phone"></img> <small><a className="footerLink" href="tel:+49">+49</a></small>
                                </li>
                                <li>
                                    <img src={fax} alt="Fax" className="phone"></img> <small><a className="footerLink" href="tel:+49">+49</a></small>
                                </li>
                            </ul>
                        </div>
                    </div>
                </div>
            </footer>
        );
    }
}

export default withRouter(Footer);

What I'm doing wrong? Why it is not working, when I click on a link?

Got it working now. I needed to change <HashRouter> to <Router>. Then it works fine.

UPDATE: This solution solves the problem, but then there is a different problem: When I have navigated and refresh the page, then an error (404) is thrown, because there is of course no such a page on the server.

I need to get the HashRouter work.

Switch is re-mounting the same component on route change · Issue , When route is changed, UsersIndex component is not re-mounted, only ReactDOM.render(( <Router history={history}> <div> <Switch>  Components not re-rendering on route change - React HashRouter I've got a problem with react and react-router . When I click on a link (in my example contact in Footer.js ), the url changes, but the desired component Location is not shown.

When you declare your routes in App.js, you should pass the props to the component:

components: props => <Location {...props} <insert other props> />

You should stick to the <Router> solution as having unnecessary hash in the url is ugly.

When I have navigated and refresh the page, then an error (404) is thrown, because there is of course no such a page on the server.

To resolve this, you need to set up a redirect to redirect all requests to the base url for the React app to handle (the url displayed will be preserved).

On Netlify, you can create a _redirects file in your public folder with the content:

/*  /index.html  200

On AWS S3, the redirect rules can be set in S3 or CloudFront, see the answers here.

For Google Cloud bucket, see this.

For Github pages, see this.

Components don't re-render when hash location changes · Issue , When my route changes from /user/123 to /user/456 my handler doesn't update to Components don't re-render when hash location changes #292 and componentWillMount does not get called when the route changes. See the master-detail example https://github.com/rackt/react-router/blob/master/  Dismiss Join GitHub today. GitHub is home to over 40 million developers working together to host and review code, manage projects, and build software together.

In your Route component you use component prop to pass the Location component (instead of render or children props available on Route) the router uses React.createElement to create a new React element from the given component. That means if you provide an inline function to the component prop, you would create a new component every render. This results in the existing component unmounting and the new component mounting instead of just updating the existing component. When using an inline function for inline rendering, use the render or the children prop.However in your case it seems you are using it for no reason so you should just pass the component and not an inline function that returns it like so :

const routes = [
      { 
        path: '/',
        exact: true,
        components: <Home key="home" currentLanguage={this.state.currentLanguage}/>

      },
      { 
        path: '/contact',
        exact: true,
        components: <Location key="locations" currentLanguage={this.state.currentLanguage} country={this.state.countryObject} contacts= {this.state.contacts} onCountryChange={this.handleCountryChange.bind(this)} />
      },
    ]

React: Re-render a Component On Route (or props) Change, React: Re-render a Component On Route (or props) Change "react-dom"; import { HashRouter, Switch, Route } from "react-router-dom"; import AJAX calls but the problem is, clicking on a link does not trigger a remount. Changes URL but not actual component that is supposed to be rendered on each route. 👍 21 cameronb23 changed the title Links change URL but not render Links change URL but not rendered component Apr 14, 2017

Make your routes use Component as below

import {IndexRoute, Route} from 'react-router';

 <Route component={App}>
    <Route path='/locations' component={LocationComponent}/>
 </Route>

This is what I am doing in my current project without using HashRouter.

Currently, When you do

<Route key={index} path={route.path} exact={route.exact} component={route.components} />

I don't think {route.components} treats it as a component.

Route, The child elements to render. Note: On React < 16 you must use a single child element since a render method cannot return more than one element. If you need​  The <Route/> component is one of the most important building blocks in the React Router package. It renders the appropriate user interface when the current location matches the route’s path .

Could be a problem with withRouter().

Have you seen this? https://github.com/ReactTraining/react-router/issues/5037

React Router: Declarative Routing for React.js, Primary ComponentsServer RenderingCode SplittingScroll <HashRouter> Since we're building a web app, we'll use react-router-dom in this guide. The route /topics loads the Topics component, which renders any further <Route> 's all topics, or the page that is shown when no topic is selected */} <Switch> <​Route  React Router is the de-facto React routing library, and it’s one of the most popular projects built on top of React. React at its core is a very simple library, and it does not dictate anything about routing. Routing in a Single Page Application is the way to introduce some features to navigating the app through links,

Programmatic Navigation in React using react-router, It already comes loaded in the react-router-dom library. path, you can simply change the state to re-render the component, thus history prop in components which are not immediate children to the <Route> components. The one from the store is up to date (showing that the component actually re-rendered after the path change) and the other is not (showing that wherever withRouter and Route take the path from is still stale at the time of the render).

Basics of React Router v4, React Router gives us components like Route, Link, Switch, Prompt etc. to work with. When hash based URL changes, browser does not reload the page, but and HashRouter components which is starting point of your application. Router also takes render prop where instead passing a component,  <HashRouter>. A <Router> that uses the hash portion of the URL (i.e. window.location.hash) to keep your UI in sync with the URL. IMPORTANT NOTE: Hash history does not support location.key or location.state. In previous versions we attempted to shim the behavior but there were edge-cases we couldn't solve.

Understanding The Fundamentals of Routing in React, Components not re-rendering on route change - React HashRouter - javascript. Footer.js), the url changes, but the desired component Location is not shown. We will create React app which will use context and HashRouter. The will fetch data from API and supply all app with data. It is an easy way to create an app without the backend using free API as a…

Comments
  • Why does your code have multiple HashRouters?
  • I've changed my code with only one HashRouter. Please see my update. It still does not work.
  • Have a look at this, it might help you : stackoverflow.com/questions/50208165/…
  • How are you deploying your website? eg. AWS S3, Netlify, Github pages?
  • It is just a standard webserver hosted by apache, i assume. But the functionality is not even there when I develop the web page with npm and node.js on my development system.
  • Please see my comment above. Standard web server with apache. I do not understand what exactly you mean with "you should pass the props to the component.". I'm doing it this way, don't I? Please see the App.js code.
  • In your App.js, you have components: () => <Location ... />. You did not define the props parameter and pass it to the Location component, like what I did above.
  • See askubuntu.com/questions/484986/… or sej-ko.dk/2017/03/29/… on how to redirect all routes to index.html.
  • Can you try hosting it on another platform (Netlify etc) to see if the problem is with your Apache redirect configuration?
  • But it does not work with npm and node.js in development as well.
  • Your explanation makes sense. However, I need several components per route. My code above is simplified. For example, I have a home route with several components in it. How do I realize this without inline function?
  • I have tried your solution, but it does not work either. The url changes, but not the component(s).
  • The issue is that it is working without HashRouter. As I wrote, it works with standard Router. But then I'm facing other issues.
  • @dns_nx, can't you separate out your components in some jsx or ts files? this way you won't get 404
  • @dns_nx No, I mean did you read the Github issue. It says you must implement shouldComponentUpdate if you want components nested deep down to update on location change. github.com/ReactTraining/react-router/issues/…