以编程方式导航使用反应
我正在开发中,我检查,如果用户不是一个应用程序loggedIn
我一定要显示登录表单,否则dispatch
的action
将改变路线和加载其他组件。 这是我的代码:
render() {
if (isLoggedIn) {
// dispatch an action to change the route
}
// return login component
<Login />
}
我怎么能实现这一点,因为我不能改变内部渲染功能的状态。
考虑到你正在使用react-router v4
在withRouter
使用你的组件,并使用道具的history.push
改变路线。 只有当你的组件没有收到Router
道具时,你才需要使用withRouter
当你的组件是由路由器渲染的组件的嵌套子withRouter
,并且你没有将路由器道具传递给它或当该组件根本没有链接到路由器,并且作为路由的单独组件呈现。
import {withRouter} from 'react-router';
class App extends React.Component {
...
componenDidMount() {
// get isLoggedIn from localStorage or API call
if (isLoggedIn) {
// dispatch an action to change the route
this.props.history.push('/home');
}
}
render() {
// return login component
return <Login />
}
}
export default withRouter(App);
重要的提示
如果使用withRouter
来防止更新被shouldComponentUpdate
阻塞,那么使用withRouter
包装实现shouldComponentUpdate
的组件是非常重要的。 例如,使用Redux时:
//这会绕过shouldComponentUpdate
withRouter(connect(...)(MyComponent))
//这不是
connect(...)(withRouter(MyComponent))
或者你可以使用重定向
import {withRouter} from 'react-router';
class App extends React.Component {
...
render() {
if(isLoggedIn) {
return <Redirect to="/home"/>
}
// return login component
return <Login />
}
}
使用react-router v2 or react-router v3
,您可以利用context
来动态更改路由
class App extends React.Component {
...
render() {
if (isLoggedIn) {
// dispatch an action to change the route
this.context.router.push('/home');
}
// return login component
return <Login />
}
}
App.contextTypes = {
router: React.PropTypes.object.isRequired
}
export default App;
或使用
import { browserHistory } from 'react-router';
browserHistory.push('/some/path');
在反应路由器版本4中:
import React from 'react'
import { BrowserRouter as Router, Route, Redirect} from 'react-router-dom'
const Example = () => (
if (isLoggedIn) {
<OtherComponent />
} else {
<Router>
<Redirect push to="/login" />
<Route path="/login" component={Login}/>
</Router>
}
)
const Login = () => (
<h1>Form Components</h1>
...
)
export default Example;
另一种方法是使用Thunk风格的异步操作(这是安全的/允许有副作用)处理这个问题。
如果使用Thunk,则可以使用thunk.withExtraArgument
将相同的history
对象注入到<Router>
组件和Thunk操作中,如下所示:
import React from 'react'
import { BrowserRouter as Router, Route, Redirect} from 'react-router-dom'
import { createBrowserHistory } from "history"
import { applyMiddleware, createStore } from "redux"
import thunk from "redux-thunk"
const history = createBrowserHistory()
const middlewares = applyMiddleware(thunk.withExtraArgument({history}))
const store = createStore(appReducer, middlewares)
render(
<Provider store={store}
<Router history={history}>
<Route path="*" component={CatchAll} />
</Router
</Provider>,
appDiv)
然后在你的动作创建者中,你将有一个可以安全使用ReactRouter的history
实例,所以如果你没有登录,你可以触发一个常规的Redux事件:
// meanwhile... in action-creators.js
export const notLoggedIn = () => {
return (dispatch, getState, {history}) => {
history.push(`/login`)
}
}
这样做的另一个好处是,url现在更容易处理,因此我们可以将重定向信息放在查询字符串中,等等。
你可以尝试在你的Render方法中进行这种检查,但是如果它导致问题,你可能会考虑在componentDidMount
中或生命周期中的其他地方使用它(虽然我也理解要坚持使用无状态功能组件)!
您仍然可以使用Redux和mapDispatchToProps
将动作创建器注入到您的组件中,因此组件仍然只是松散地连接到Redux。