react-router-dom 路由组件需要页面重新加载
Posted
技术标签:
【中文标题】react-router-dom 路由组件需要页面重新加载【英文标题】:react-router-dom route component requires page reload 【发布时间】:2018-08-31 06:13:39 【问题描述】:当调用 history.push('/packages') 时,url 会更新,但除非重新加载页面,否则组件不会挂载(渲染)。如果我调用 createHistory(forceRefresh: true) 或手动重新加载页面,则 UI 会正确呈现。如何配置 react-router-dom 以加载组件而不显式重新加载页面或使用 forceRefresh?
index.jsx
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
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><h3>Mythos</h3></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
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
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 (
<div className="col-lg-12">
this.props.results ?
<PackageList results=this.props.results /> :
<h3>No Packages Available</h3>
</div>
);
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
【问题讨论】:
尝试<Route path='/packages' render=PackageContainer />
并从您的代码中删除withRouter
【参考方案1】:
我假设,您正在创建 history
对象的新实例,但 BrowserRouter
不知道其中发生的变化。
因此,您应该创建历史对象并将其导出到 index.jsx
并使用 Router
而不是 BrowserRouter
并作为 history
属性传递,这样您就可以在需要时导入它。
例如:
index.jsx
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
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
希望它会有所帮助。
【讨论】:
这行得通,谢谢!那么,我是否需要使用 Router 而不是 BrowserRouter,因为我使用的是 redux? @neridaj 不完全是。实际上,BrowserRouter
忽略了 history 属性,所以我们应该使用自定义历史并将其传递给 Router
。在这种情况下,它没有与Redux
连接。【参考方案2】:
在 App.jsx 中
<Switch>
<Route path='/packages' render=(props) => <PackageContainer ...props/> />
<Route exact path='/' render=(props) => <LoginFormContainer ...props/> />
</Switch>
现在 PackageContainer 和 LoginFormContainer 都可以访问 history 对象
【讨论】:
以上是关于react-router-dom 路由组件需要页面重新加载的主要内容,如果未能解决你的问题,请参考以下文章
页面未呈现;在 react-router-dom 中使用受保护的路由将道具传递给孩子时