关于reactjs:react-router-dom路由组件需要页面重新加载

react-router-dom route component requires page reload

在调用history.push('/ packages')时,URL已更新,但除非重新加载页面,否则组件不会安装(渲染)。如果我调用createHistory({forceRefresh:true})或手动重新加载页面,则UI会正确呈现。如何配置react-router-dom以加载组件而无需显式重新加载页面或使用forceRefresh?

index.jsx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import React from 'react'
import ReactDOM from 'react-dom'
import { BrowserRouter } from 'react-router-dom'
import store from './store'
import {Provider} from 'react-redux'
import App from './App'

ReactDOM.render(
  <Provider store={store}>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </Provider>,
  document.getElementById('app')
);

App.jsx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import React, { Component } from 'react'
import { Switch, Route } from 'react-router-dom'
import PropTypes from 'prop-types'
import { Navbar, PageHeader, Grid, Row, Col } from 'react-bootstrap'
import LoginFormContainer from './components/Login/LoginFormContainer'
import PackageContainer from './components/Package/PackageContainer'

class App extends Component {
  render() {
    return (
      <Grid>
        <Navbar>
          <Navbar.Header>
            <Navbar.Brand>Mythos</Navbar.Brand>
          </Navbar.Header>
        </Navbar>
        <Row className="content">
          <Col xs={12} md={12}>
            <Switch>
              <Route path='/packages' render={() => <PackageContainer />} />
              <Route exact path='/' render={() => <LoginFormContainer />} />
            </Switch>
          </Col>
        </Row>
      </Grid>
    )
  }
}

export default App

loginActions.jsx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import * as types from './actionTypes'
import LoginApi from '../api/loginApi'
import createHistory from 'history/createBrowserHistory'

const history = createHistory()

export function loginUser(user) {
  return function(dispatch) {
    return LoginApi.login(user).then(creds => {
      dispatch(loginUserSuccess(creds));
    }).catch(error => {
      throw(error);
    });
  }
}

export function loginUserSuccess(creds) {
  sessionStorage.setItem('credentials', JSON.stringify(creds.data))
  history.push('/packages')
  return {
    type: types.LOGIN_USER_SUCCESS,
    state: creds.data
  }
}

PackageContainer.jsx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import React, { Component } from 'react'
import {connect} from 'react-redux'
import PropTypes from 'prop-types'
import {loadPackages} from '../../actions/packageActions'
import PackageList from './PackageList'
import ImmutablePropTypes from 'react-immutable-proptypes'
import {Map,fromJS,List} from 'immutable'
import {withRouter} from 'react-router-dom'

class PackageContainer extends Component {
  constructor(props, context) {
    super(props, context);
  }
  componentDidMount() {
    this.props.dispatch(loadPackages());
  }
  render() {
    return (
     
        {this.props.results ?
        <PackageList results={this.props.results} /> :
        No Packages Available}
     
    );
  }
}

PackageContainer.propTypes = {
  results: ImmutablePropTypes.list.isRequired,
};

const mapStateToProps = (state, ownProps) => {
  return {
    results: !state.getIn(['packages','packages','results']) ? List() : state.getIn(['packages','packages','results'])
  };
}

PackageContainer = withRouter(connect(mapStateToProps)(PackageContainer))

export default PackageContainer


我认为,这个问题是您正在创建history对象的新实例,但BrowserRouter不知道它内部发生的更改。

因此,您应该创建历史记录对象并将其导出到index.jsx中,并使用Router而不是BrowserRouter并作为history属性传递,这样便可以在需要时将其导入。

例如:

index.jsx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { Router } from 'react-router-dom'
import createHistory from 'history/createBrowserHistory'
...

export const history = createHistory()

ReactDOM.render(
  <Provider store={store}>
    <Router history={history}>
      <App />
    </Router>
  </Provider>,
  document.getElementById('app')
);

然后,在loginActions中,您只需导入history并像以前一样使用.push方法。

loginActions.jsx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import * as types from './actionTypes'
import LoginApi from '../api/loginApi'
import { history } from './index'

export function loginUser(user) {
  return function(dispatch) {
    return LoginApi.login(user).then(creds => {
      dispatch(loginUserSuccess(creds));
    }).catch(error => {
      throw(error);
    });
  }
}

export function loginUserSuccess(creds) {
  sessionStorage.setItem('credentials', JSON.stringify(creds.data))
  history.push('/packages')
  return {
    type: types.LOGIN_USER_SUCCESS,
    state: creds.data
  }
}

希望这会有所帮助。


在App.jsx

1
2
3
4
<Switch>
     <Route path='/packages' render={(props) => <PackageContainer {...props}/>} />
     <Route exact path='/' render={(props) => <LoginFormContainer {...props}/>} />
 </Switch>

现在PackageContainer和LoginFormContainer都可以访问历史记录对象