react-router4改变了URL,route不匹配新的URL重新渲染组件

#1

如题,我用react-router4做登录的路由,当我登陆成功后,改变store中存储的currentURL,然后Router中监听到store的变化,用this.setState()改变Router的state,用History改变了页面的URL,并试图引起页面组件路由的重新渲染,render确实被调用了,路由却没有渲染新对应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;

此时如果刷新页面,则会渲染相应的新组件:

我在检测生命周期,发现componentWillUpdate和render执行之后,componentDIdUpdate并不执行。
不知道是不是render出错。

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

而在LoginPage的render和SuccessPage分别插入alert,发现走的是LoginPage的渲染和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>);
}

调试两天了,无果,望各位指点一二

1 Like
#2

一时半会看不出问题. 要说不一样的地方, 我们这边用 React Router 的时候, 状态是直接留在 React Router 组件内部的, 而不会放到 store 里面去, 因为从 React Router 提取状态会担心状态不同步, 所以平时直接用 this.props.history.push('/xxx) 了.

#3

可是我换成固定的也没有效果,如下:

this.props.history.push('/SuccessPage');
#4

我觉得主要的问题在于render中route匹配的路径还是之前的LoginPage路劲,并没有匹配新的SuccessPage路径

  render() {
    console.debug("render:" + this.props.history.location.pathname);
    return (<BrowserRouter >
      <Switch>
        <Route exact="exact" path="/" component={errorPage}/>
        <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>
    </BrowserRouter>);
  }

但匹配之前render()方法内输出this.props.history.location.pathname确实又是新的路径

#7

好奇怪… 想不出来原因.

#8

唉,但还是谢谢你的解答~