React router v4 使用声明式重定向而不渲染当前组件
React router v4 use declarative Redirect without rendering the current component
我正在使用类似 this 的代码在用户登录后在我的应用程序中重定向。代码如下所示:
import React, { Component } from 'react'
import { Redirect } from 'react-router'
export default class LoginForm extends Component {
constructor () {
super();
this.state = {
fireRedirect: false
}
}
submitForm = (e) => {
e.preventDefault()
//if login success
this.setState({ fireRedirect: true })
}
render () {
const { from } = this.props.location.state || '/'
const { fireRedirect } = this.state
return (
<div>
<form onSubmit={this.submitForm}>
<button type="submit">Submit</button>
</form>
{fireRedirect && (
<Redirect to={from || '/home'}/>
)}
</div>
)
}
}
触发成功登录后工作正常。但有一种情况,登录用户进入登录页面,应该自动重定向到 "home" 页面(或任何其他页面)。
如何在不渲染当前组件且不(据我了解)强制推送到历史记录(例如在componentWillMount
中)的情况下使用重定向组件?
解决方案 1
您可以使用 withRouter
HOC 通过道具访问历史记录。
导入路由器。
import {
withRouter
} from 'react-router-dom';
然后用 HOC 包装。
// Example code
export default withRouter(connect(...))(Component)
现在您可以访问 this.props.history
。例如与 componentDidMount()
.
一起使用
componentDidMount() {
const { history } = this.props;
if (this.props.authenticated) {
history.push('/private-route');
}
}
解决方案 2 好多了
这是 reacttraining 上的示例。
哪个最适合你。
但是您只需要创建 LoginRoute
来处理您描述的问题。
const LoginRoute = ({ component: Component, ...rest }) => (
<Route
{...rest} render={props => (
fakeAuth.isAuthenticated ? (
<Redirect to={{
pathname: '/private-route',
state: { from: props.location }
}} />
) : (
<Component {...props} />
)
)} />
);
并在 <Router />
内替换
<Route path="/login" component={Login}/>
与
<LoginRoute path="/login" component={Login}/>
现在,每当有人尝试以经过身份验证的用户身份访问 /login
路由时,他都会被重定向到 /private-route
。这是更好的解决方案,因为如果不满足条件,它不会挂载您的 LoginComponent
。
这是另一个解决方案,根本不涉及 React 的东西。例如。如果你需要在 redux-saga 中导航。
有文件history.js:
import {createBrowserHistory} from 'history';
export default createBrowserHistory();
在你定义路由的地方,不要使用浏览器路由器,而只是一般的 <Router/>
:
import history from 'utils/history';
...
<Router history={history}>
<Route path="/" component={App}/>
</Router>
就是这样。现在您可以使用相同的历史导入并推送新路由。
在您应用的任何部分:
import history from 'utils/history';
history.push('/foo');
在saga中:
import {call} from 'redux-saga/effects';
import history from 'utils/history';
...
history.push('/foo');
yield call(history.push, '/foo');
我正在使用类似 this 的代码在用户登录后在我的应用程序中重定向。代码如下所示:
import React, { Component } from 'react'
import { Redirect } from 'react-router'
export default class LoginForm extends Component {
constructor () {
super();
this.state = {
fireRedirect: false
}
}
submitForm = (e) => {
e.preventDefault()
//if login success
this.setState({ fireRedirect: true })
}
render () {
const { from } = this.props.location.state || '/'
const { fireRedirect } = this.state
return (
<div>
<form onSubmit={this.submitForm}>
<button type="submit">Submit</button>
</form>
{fireRedirect && (
<Redirect to={from || '/home'}/>
)}
</div>
)
}
}
触发成功登录后工作正常。但有一种情况,登录用户进入登录页面,应该自动重定向到 "home" 页面(或任何其他页面)。
如何在不渲染当前组件且不(据我了解componentWillMount
中)的情况下使用重定向组件?
解决方案 1
您可以使用 withRouter
HOC 通过道具访问历史记录。
导入路由器。
import {
withRouter
} from 'react-router-dom';
然后用 HOC 包装。
// Example code
export default withRouter(connect(...))(Component)
现在您可以访问 this.props.history
。例如与 componentDidMount()
.
componentDidMount() {
const { history } = this.props;
if (this.props.authenticated) {
history.push('/private-route');
}
}
解决方案 2 好多了
这是 reacttraining 上的示例。
哪个最适合你。
但是您只需要创建 LoginRoute
来处理您描述的问题。
const LoginRoute = ({ component: Component, ...rest }) => (
<Route
{...rest} render={props => (
fakeAuth.isAuthenticated ? (
<Redirect to={{
pathname: '/private-route',
state: { from: props.location }
}} />
) : (
<Component {...props} />
)
)} />
);
并在 <Router />
内替换
<Route path="/login" component={Login}/>
与
<LoginRoute path="/login" component={Login}/>
现在,每当有人尝试以经过身份验证的用户身份访问 /login
路由时,他都会被重定向到 /private-route
。这是更好的解决方案,因为如果不满足条件,它不会挂载您的 LoginComponent
。
这是另一个解决方案,根本不涉及 React 的东西。例如。如果你需要在 redux-saga 中导航。
有文件history.js:
import {createBrowserHistory} from 'history';
export default createBrowserHistory();
在你定义路由的地方,不要使用浏览器路由器,而只是一般的 <Router/>
:
import history from 'utils/history';
...
<Router history={history}>
<Route path="/" component={App}/>
</Router>
就是这样。现在您可以使用相同的历史导入并推送新路由。
在您应用的任何部分:
import history from 'utils/history';
history.push('/foo');
在saga中:
import {call} from 'redux-saga/effects';
import history from 'utils/history';
...
history.push('/foo');
yield call(history.push, '/foo');