我需要使用 react-router-4 实现注册流程。流包括以下步骤:
- 创建帐户(电子邮件/通行证)
- 确认电子邮件
- 创建个人资料(个人资料详细信息,如城市,年龄等,必填字段)
申请要求:
- 如果用户未登录,则应始终将他重定向到
Login
页面 - 如果用户登录,但电子邮件未确认,则应始终将他重定向到
ConfirmEmail
页面(无论他在URL地址栏中输入什么URL,即使在几天后加载应用程序后) - 如果用户确认了电子邮件,但尚未创建个人资料,我希望他始终被重定向到
CreateProfile
页面
因此,如果用户没有完成某个步骤,我希望始终将他重定向到此步骤(即使在重新加载应用程序后,无论他在浏览器中输入什么 URL)。
作为一种选择,我想限制用户访问ConfirmEmail
如果他已经确认的页面(或者如果他已经创建了配置文件,则限制对CreateProfile
页面的访问)。
如何使用 React 路由器 4 优雅地实现此逻辑?我认为这是应用程序的核心/基本功能,所以我正在寻找好的、可扩展的解决方案。
我也在使用 Redux,所以请注意,在某些时候我已经有以下 Redux 状态的变量:isLoggedIn
、isEmailConfirmed
、isProfileCreated
。
谢谢。
您没有指定如何或何时设置isLoggedIn
、isEmailConfirmed
、isProfileCreated
,因此我假设在渲染开始之前,它们已经以某种方式在 redux 存储中设置。
我认为完成此任务的最佳工具是使用类似于 RR4 文档中的身份验证工作流示例的内联Route
渲染。
我已经制作了示例CRA应用程序,可以满足您的要求。
如果在redux/index中更改属性值.js:
const INITIAL_STATE = {
isLoggedIn: false,
isEmailConfirmed: false,
isProfileCreated: false,
}
。无论您尝试访问哪个 URL,该应用程序都将使用它来呈现适当的视图。例如,如果您设置了isEmailConfirmed=true和isProfileCreated=false,那么您唯一可以访问的路由是/create-profile
(CreateProfile组件)。 但是,如果用户完成了注册步骤的每一步,并且isProfileCreated=true,他将可以访问除注册之外的所有路由。
名为AuthorizedRoute
的增强Route
:
import React from 'react'
import { Redirect, Route } from 'react-router-dom'
import { connect } from 'react-redux'
const AuthorizedRoute = ({ component: Component, isProfileCreated, isEmailConfirmed, isLoggedIn, ...rest }) => (
<Route {...rest} render={props => {
//-- if user is fully registered - grant him every route except registration steps.
if (isProfileCreated) {
if (['/', '/create-account', '/create-profile', '/confirm-email'].includes(props.location.pathname)) {
return <Redirect to="/dashboard" />
} else {
return <Component {...props} />
}
}
//-- user is not fully registered so he needs to be redirected to next step...
if (isEmailConfirmed) {
if (props.location.pathname === '/create-profile') {
return <Component {...props} />
} else {
return <Redirect to="/create-profile" />
}
}
if (isLoggedIn) {
if (props.location.pathname === '/confirm-email') {
return <Component {...props} />
} else {
return <Redirect to="/confirm-email" />
}
}
//-- ... or allowed to use `Login` or `CreateAccount` page
if (props.location.pathname === '/' || props.location.pathname === '/create-account') {
return <Component {...props} />
}
return <Redirect to="/" />
}} />
)
export default connect(
(state) => ({
isProfileCreated: state.isProfileCreated,
isEmailConfirmed: state.isEmailConfirmed,
isLoggedIn: state.isLoggedIn,
}),
)(AuthorizedRoute)
以下是了解此逻辑的已定义组件:
class App extends Component {
render () {
return (
<div>
<nav>
<Link to="/">login</Link>
<Link to="/create-account">create account</Link>
<Link to="/confirm-email">confirm email</Link>
<Link to="/create-profile">create profile</Link>
<Link to="/dashboard">dashboard</Link>
</nav>
<Switch>
<AuthorizedRoute exact path="/" component={Login} />
<AuthorizedRoute path="/create-account" component={CreateAccount} />
<AuthorizedRoute path="/confirm-email" component={ConfirmEmail} />
<AuthorizedRoute path="/create-profile" component={CreateProfile} />
<AuthorizedRoute path="/dashboard" component={Dashboard} />
<Redirect to="/" />
</Switch>
</div>
)
}
}
我认为最困难的部分是真正正确地识别用户以及他被允许或不做什么。除此之外,这只是识别他试图访问的路线并渲染该路线或重定向的问题。