React-router4 changed the URL,route mismatch with the new URL re-rendering component

as mentioned above, I use react-router4 to route my login. When I log in successfully, change the currentURL, stored in store and then listen to the change of store in Router, change the state, of Router with this.setState (), change the URL, of the page with History and try to cause the re-rendering of the page component. Render is indeed called, but the route does not render the component of the new corresponding URL.

index.js

import React from "react";
import ReactDOM from "react-dom";
import registerServiceWorker from "./registerServiceWorker";
import Routes from "./Routes.js";
import store from "./Store.js";
import {Provider} from "react-redux";
import "./css/bootstrap.min.css";
import "./css/navbar/chartist-custom.css";
import "./css/navbar/main.css";
import "./css/navbar/font-awesome.min.css";
import "./css/navbar/style.css";
import {createBrowserHistory} from "history"

const history = createBrowserHistory();

ReactDOM.render(<Provider store={store}>
  <Routes history={history} /></Provider>, document.getElementById("root"));
registerServiceWorker();

Routes.js

import React, {Component} from "react";
import {
  Route,
  Switch,
  Link,
  BrowserRouter,
  Router,
  Redirect
} from "react-router-dom";
import LoginPage from "./views/pages/LoginPage.js";
import SuccessPage from "./views/pages/SuccessPage.js";
import errorPage from "./views/pages/errorPage.js";
import store from "./Store.js";

class Routes extends Component {

  constructor(props) {
    super(props);
    this.URLChange = this.URLChange.bind(this);
    this.getOwnState = this.getOwnState.bind(this);

    this.state = this.getOwnState();
  }

  getOwnState() {
    return {
      currentURL: store.getState()["currentURL"]
    };
  }

  URLChange() {
    console.debug(this.getOwnState()["currentURL"]);
    this.props.history.push(this.getOwnState()["currentURL"]);

    //setState
    let currentURL = this.getOwnState()["currentURL"];
    this.setState(Object.assign({
      currentURL
    }, {currentURL}), () => {
      //
      console.debug("1:" + this.state.currentURL)
    })

  }

  componentDidMount() {
    store.subscribe(this.URLChange);
  }

  render() {
    alert("render:" + JSON.stringify(this.props.history.location.pathname));
    return (<BrowserRouter >
      <Switch>
        <Route path="/LoginPage" component={LoginPage}/>
        <Route path="/SuccessPage" component={SuccessPage}/>
        <Route path="/errorPage" component={errorPage}/>
        <Route path="/*" component={errorPage}/>
      </Switch>
    </BrowserRouter>);
  }
}

export default Routes;

:

debugging for a whole day, but to no avail, I hope you can give me some advice

< hr >

update:
I was examining the lifecycle and found that after componentWillUpdate and render were executed, componentDIdUpdate did not execute.
I don"t know if there is a render error.

  componentWillUpdate() {
    alert("componentWillUpdate");
  }
  componentDIdUpdate() {
    alert("componentDIdUpdate");
  }

while inserting alert, into render and SuccessPage of LoginPage respectively, it is found that it is the rendering of LoginPage and alert:

.

LoginPage.js

//
function LoginPage({login}) {
  alert("LoginPage");
  return (<div>
    <Panel style={PanelStyle}>
      <Image src={require("../../img/logo.png")} style={ImageStyle}/>
      <div style={TitleStyle}></div>
      <FormGroup>
        <FormControl type="text" placeholder="" onChange={accountChange}/>
      </FormGroup>
      <FormGroup>
        <FormControl type="password" placeholder="" onChange={passwordChange}/>
      </FormGroup>
      <br/>
      <Button className="btn-block" bsStyle="primary" onClick={login}></Button>
    </Panel>
  </div>);
}

SuccessPage.js

//
function SuccessPage() {
  alert("SuccessPage");
  return (<div>SuccessPage
  </div>);
}
Mar.13,2021

    I have looked it up on
  • Stack Overflow for a long time, but I still haven't found the point.
  • shouldComponentUpdate (nextProps, nextState) writes this.context.router.history.push ("/ path") in this method; causes it to fail to render
  • has put the final code up
import React from 'react';
import ReactDOM from 'react-dom';
import registerServiceWorker from './registerServiceWorker';
import Routes from './Routes.js';
import store from './Store.js';
import {Provider} from 'react-redux';
import './css/bootstrap.min.css';
import './css/navbar/chartist-custom.css';
import './css/navbar/main.css';
import './css/navbar/font-awesome.min.css';
import './css/navbar/style.css';
import {BrowserRouter} from 'react-router-dom';


const App = () => {
  return (<Provider store={store}>
    <BrowserRouter><Routes/></BrowserRouter>
  </Provider>);
}

ReactDOM.render(<App/>, document.getElementById('root'));

registerServiceWorker();
import React, {Component} from 'react';
import {
  Route,
  Switch,
  Link,
  BrowserRouter,
  Router,
  Redirect,
  withRouter
} from 'react-router-dom';
import LoginPage from './views/pages/LoginPage.js';
import SuccessPage from './views/pages/SuccessPage.js';
import errorPage from './views/pages/errorPage.js';
import store from './Store.js';
import {Provider} from 'react-redux';
import PropTypes from 'prop-types'

class Routes extends Component {

  constructor(props, context) {
    super(props, context);

    this.URLChange = this.URLChange.bind(this);
    this.getOwnState = this.getOwnState.bind(this);

    this.state = this.getOwnState();
  }

  static contextTypes = {
    router: PropTypes.object
  }


  getOwnState() {
    return {
      currentURL: store.getState()["currentURL"]
    };
  }

  URLChange() {
    console.debug(this.getOwnState()["currentURL"]);

    //setState
    let currentURL = this.getOwnState()["currentURL"];
    this.setState(Object.assign({
      currentURL
    }, {currentURL}), () => {
      //
      console.debug("this.state.currentURL:" + this.state.currentURL)
      console.debug("URL:" + this.context.router.history.location.pathname);
      console.debug("URL:" + this.getOwnState()["currentURL"]);
      //
      this.context.router.history.push(this.getOwnState()["currentURL"]);
    })

  }
  componentDidMount() {
    store.subscribe(this.URLChange);
  }

  render() {
    return (<div>
      <Link to="/LoginPage">LoginPage</Link>
      <br/>
      <Link to="/SuccessPage">SuccessPage</Link>
      <br/>
      <Link to="/errorPage">errorPage</Link>
      <br/>
      <Switch>
        <Route exact="exact" path="/" component={LoginPage}/>
        <Route exact="exact" path="/LoginPage" component={LoginPage}/>
        <Route exact="exact" path="/SuccessPage" component={SuccessPage}/>
        <Route exact="exact" path="/errorPage" component={errorPage}/>
        <Route exact="exact" path="/*" component={errorPage}/>
      </Switch>
    </div>);
  }
  componentWillUpdate() {}
  componentDIdUpdate() {}

}

export default withRouter(Routes);

in the process of using react-router-dom, I believe many people have encountered this problem. Here are two solutions

Note: the key point lies in two different ways of using Router

// 4.0Routerhistory
import { BrowserRouter as Router } from 'react-router-dom';

// 4.03.0Routerhistory
import { Router } from 'react-router-dom';

solution 1: officially recommended by history 4.0, import history to components that need to use history using withRouter

login.js

import { withRouter } from 'react-router-dom';

const Login = ({history}) => {
    history.push('/user'); // 
    return null;
};

export default withRouter(Login); 

app.js

import { BrowserRouter, Route, Link, Switch } from 'react-router-dom';
import Login from './login';

const Home = () => (
    <div>Home
        <Link to="login">login</Link>
    </div>
)

export default () => (
    <BrowserRouter>
        <Switch>
            <Route exact path="/" component={Home} />
            <Route path="/home" component={Home} />
            <Route path="/login" component={Login} />
        </Switch>
    </BrowserRouter>
);

solution 2history, 3.0 usage (an advantage of this use is that history can be called anywhere, for example, you can introduce history, into the axios interceptor to complete front-end redirection when the token expires)

history.js

import createHistory from 'history/createBrowserHistory';

export default createHistory();

app.js

import { Router } from 'react-router-dom';
import history from './history';

const Login = () => {
    return <div>Login</div>;
};

export default () => (
    <Router history={ history }>
        <Route path="/login" component={Login} />
    </Router>
);

xxx.js

import history from './history';
   
history.push('/login'); //  

to tell you the truth, I have encountered the same problem, and I haven't found the reason so far. Finally, a small idea is to refresh the current page asynchronously after the route change.

history.push('/somePath'); // 
setTimeout(() => {
    window.location.reload();
}, 0);
Menu