如何在使用高阶组件进行身份验证时延迟检查redux存储
how to delay checking redux store when authenticating using Higher Order Components
我使用的是react、redux、react路由器和更高阶的组件。我有一些受保护的路由,用户需要登录才能查看,我已经将这些路由封装在一个更高阶的组件中,我会尽可能清楚地给出上下文,所以请耐心等待。这是我的高阶组件(HOC):
import React from 'react';
import {connect} from 'react-redux';
import { browserHistory } from 'react-router';
export function requireAuthentication(Component, redirect) {
class AuthenticatedComponent extends React.Component {
componentWillMount() {
this.checkAuth();
}
componentWillReceiveProps(nextProps) {
this.checkAuth();
}
checkAuth() {
if (!this.props.isAuthenticated) {
browserHistory.push(redirect);
}
}
render() {
console.log('requireAuthentication render');
return (
<div>
{this.props.isAuthenticated === true
? <Component {...this.props}/>
: null
}
</div>
)
}
}
const mapStateToProps = (state) => ({
isAuthenticated: state.loggedIn
});
return connect(mapStateToProps)(AuthenticatedComponent);
}
HOC对redux存储进行检查,以查看用户是否已登录,并且它能够这样做,因为返回的Auth组件已连接到redux存储。
这就是我在使用react路由器的路由中使用HOC的方式:
import React, { Component } from 'react';
import { Router, Route, browserHistory, IndexRoute } from 'react-router';
import Nav from './nav';
import MainBody from './main-body';
import Login from './login';
import Signup from '../containers/signup';
import Dashboard from './dashboard';
import { requireAuthentication } from './require-authentication';
export default class Everything extends Component {
render() {
return (
<div>
<a className="iconav-brand intelliagg-logo-container" href="/">
<span className="iconav-brand-icon intelliagg">Deep-Light</span>
</a>
<Router history={browserHistory}>
<Route path='/' component={Login} >
</Route>
<Route path='/main' component={MainBody}>
<Route path='/dashboard' component={ requireAuthentication(Dashboard, '/') } />
<Route path='/signup' component={Signup} />
</Route>
</Router>
</div>
);
}
}
我导入HOC功能,并将受保护的路由传递给HOC,在本例中为Dashboard。如果用户未登录并尝试访问此视图,他们将被重定向到登录页面。
当用户启动登录时,这是由一个操作创建者完成的,该创建者使用用户提供的用户名和密码向服务器发出请求,我有一个reducer,它用一个写着isAuthenticated: true
:的标志更新状态
import { browserHistory } from 'react-router';
export default function(state = false, action) {
let newState;
switch (action.type) {
case 'LOGGED_IN':
newState = action.payload.data.login_status;
return newState;
break;
default:
return state;
}
}
我的减速器:
import { combineReducers } from 'redux';
import formFields from './reducer_form-fields';
import hintReducer from './reducer_hint-reducer';
import errorMessage from './reducer_error-message-submission';
import loggedIn from './reducer_logged-in';
import isAuthenticated from './reducer_isAuthenticated';
const rootReducer = combineReducers({
formInput: formFields,
hint: hintReducer,
errorMessage,
loggedIn,
isAuthenticated
});
export default rootReducer;
因此,我的问题是HOC组件总是检查isAuthenticated标志,如果它被设置为false(默认值),它会将用户重定向到登录页面。由于登录请求需要一些时间,并且状态需要更新,这意味着用户将始终重定向到登录页面,因为从HOC到redux存储的检查在客户端是即时的。
我如何根据服务器的响应进行检查并相应地重定向用户?有没有办法延迟从HOC检查存储中的冗余值?
我不同意Hayo的观点,认为使用onEnter是最好的方法。请参阅这篇SO文章,了解为什么我认为HOC解决方案(就像你使用的)是一种更好的方法:Universal Auth Redux&React路由器。
至于您的特定问题,您可以通过在reducer中添加一个isAuthenticating
布尔值并在checkAuth()
函数期间将其传递到HOC中来实现这一点。如果是真的,您可能希望显示一个替代组件,如加载条/微调器等,以向用户提供一些反馈。reducer可以将此bool默认为true,然后在LOGGED_IN
上将其设置为false。你的减速器可能看起来像这样:
const initialState = { isAuthenticating: true, isAuthenticated: false };
export default function(state = initialState, action) {
let newState;
switch (action.type) {
case 'LOGGED_IN':
newState = { isAuthenticating: false, isAuthenticated: action.payload.data.login_status };
return newState;
default:
return state;
}
}
然后在HOC的render()
中,如果isAuthenticating
为true,则可以返回LoadingComponent
而不是null。
这与我们刚刚在本PR中添加到redux auth包装器的功能非常相似https://github.com/mjrussell/redux-auth-wrapper/pull/35如果您想将其用于更多的参考
我认为应该通过使用react router配置动态路由来解决问题。您的解决方案试图在react组件中而不是在react路由器中解决问题。
换句话说,如果isAutheniated为false,则转到路由"/"。如果是Authenicated,则路由将转到仪表板或请求的任何内容。
查看页面末尾的Configuration with Plain Routes和getComponent函数。React Router也有一个onEnter属性,在您的情况下可能类似于以下属性:
module.exports = store => ({
component: require('./main.jsx'),
childRoutes: [
// public routes
{ getComponents(nextState, cb) {
return require.ensure([], (require) => {
cb(null, require('./login'))
})
},{
...
},{
onEnter: (nextState, replace) => {
const { isAuthenticated } = store.getState();
if (!isAuthenticated) {
replace('/');
}
},
// Protected routes
childRoutes: [... ]
},{
// Share the path (magic is here)
// Dynamically load the correct component
path: '/',
getComponent: (location, cb) => {
const { isAuthenticated } = store.getState();
if (isAuthenticated)
return require.ensure([], (require) => {
cb(null, require('./dashboard'))
})
}
return require.ensure([], (require) => {
cb(null, require('./signup'))
})
}
}
我希望这对解决问题有帮助,并给我们一个思路。
- 当需要身份验证时,ui路由器不会重定向
- 添加@javascript标记时,Cucumber中的HTTP身份验证失败
- 如何在使用高阶组件进行身份验证时延迟检查redux存储
- Google Drive SDK示例python DrEdit不工作(身份验证时闪烁,编辑器未显示)
- 如何在身份验证时从静态express页面提供整个angularJS SPA
- 在Internet Explorer 11中使用SoundCloud进行身份验证时出现问题
- 使用谷歌登录网页时使用的身份验证令牌是什么
- AngularJS身份验证,带有一个restful api,成功时返回一个令牌
- 对用户进行身份验证时角度闪烁
- 谷歌身份验证在登录时不会显示弹出窗口
- 在尝试检索经过身份验证的Google+用户的电子邮件地址时获取“gapi.client未定义”
- Meteor:当客户端使用 LinkedIn 登录时,首先进行身份验证时创建用户帐户
- 尝试在 Node.js 应用中执行 Google 身份验证时请求超时 (v 0.10.13)
- 护照身份验证在回调时做什么
- “用户取消了身份验证”时,从Chrome扩展程序使用AuthWithOAuthPopup
- 刷新时的 JWT 角度身份验证
- 使用 Firebase OauthToken 方法进行身份验证时出错
- MongoError: 身份验证失败.- 连接到MongoLab时出现问题
- 在JavaScript中玩游戏时的Twitter身份验证
- Angularjs在使用身份验证时路由不稳定