简体   繁体   English

组件不会在路由更改时重新呈现 - React HashRouter

[英]Components not re-rendering on route change - React HashRouter

I've got a problem with react and react-router . 我有reactreact-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. 当我点击一个链接(在我的例子在contactFooter.js ),该URL的变化,但所需的组件Location没有显示。 When I refresh the site then, the correct component is displayed. 当我刷新网站时,会显示正确的组件。

App.js: 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: 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: 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: 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> . 我需要将<HashRouter>更改为<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. 更新:这个解决方案解决了这个问题,但是有一个不同的问题:当我导航并刷新页面时,会抛出错误(404),因为服务器上当然没有这样的页面。

I need to get the HashRouter work. 我需要让HashRouter工作。

When you declare your routes in App.js , you should pass the props to the component: App.js声明路由时,应将props传递给组件:

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

You should stick to the <Router> solution as having unnecessary hash in the url is ugly. 你应该坚持<Router>解决方案,因为在url中有不必要的哈希很难看。

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. 当我导航并刷新页面时,则抛出错误(404),因为服务器上当然没有这样的页面。

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). 要解决此问题,您需要设置重定向以将所有请求重定向到基本网址以供React应用处理(显示的网址将被保留)。

On Netlify , you can create a _redirects file in your public folder with the content: Netlify上 ,您可以在公共文件夹中使用以下内容创建_redirects文件:

/*  /index.html  200

On AWS S3, the redirect rules can be set in S3 or CloudFront, see the answers here . 在AWS S3上,可以在S3或CloudFront中设置重定向规则,请参阅此处的答案

For Google Cloud bucket, see this . 对于Google Cloud存储桶,请参阅此内容

For Github pages, see this . 对于Github页面,请参阅此内容

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. 在Route组件中,您使用组件prop来传递Location组件(而不是Route上可用的render或children props),路由器使用React.createElement从给定组件创建新的React元素。 That means if you provide an inline function to the component prop, you would create a new component every render. 这意味着如果为组件prop提供内联函数,则每次渲染都会创建一个新组件。 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 : 当使用内联函数进行内联渲染时,请使用渲染或子prop.However在您的情况下,您似乎无缘无故地使用它,因此您应该只传递组件而不是返回它的内联函数,如下所示:

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)} />
      },
    ]

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. 这是我在不使用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.components}将其视为一个组件。

Could be a problem with withRouter() . 可能是withRouter()的问题。

Have you seen this? 你见过这个吗? https://github.com/ReactTraining/react-router/issues/5037 https://github.com/ReactTraining/react-router/issues/5037

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM