如何使用高阶组件进行身份验证时延迟检查redux存储

Abd*_*bdi 3 javascript authentication reactjs react-router redux

我正在使用react,redux,react-router和更高阶的组件.我有一些用户需要登录才能查看的受保护路由,我将这些路由包含在一个更高阶的组件中,我会尝试尽可能清楚地给出一个上下文,所以请耐心等待.这是我的高阶组件(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);

}
Run Code Online (Sandbox Code Playgroud)

HOC检查redux存储以查看用户是否已登录并且能够执行此操作,因为返回的Auth组件已连接到redux存储.

这就是我在使用路由器的路由中使用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>
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

我导入HOC函数,然后将受保护的路由传递给HOC,在本例中是Hashboard.如果用户未登录并尝试访问此视图,则会将其重定向到登录页面.

当用户启动登录时,这是由一个动作创建者完成的,该动作创建者使用用户提供的用户名和密码向服务器发出请求,并且我有一个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;
  }
}
Run Code Online (Sandbox Code Playgroud)

我的减速器:

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;
Run Code Online (Sandbox Code Playgroud)

所以,我的问题是HOC组件总是检查isAuthenticated标志,如果设置为false(默认值),它会将用户重定向到登录页面.由于登录请求需要一些时间并且状态需要更新,这意味着用户将始终被重定向到登录页面,因为客户端会立即从HOC到redux存储进行检查.

如何根据服务器的响应进行检查并相应地重定向用户?有没有办法延迟从HOC检查商店中的redux值?

小智 6

我不同意Hayo,因为使用onEnter是最好的方法.请参阅此SO帖子,了解为什么我认为HOC解决方案(就像您使用的)是一种更好的方法:Universal Auth Redux和React Router.

至于你的具体问题,你可以通过isAuthenticating在你的reducer中添加一个布尔值并在checkAuth()函数中将它传递给你的HOC 来实现这个目的.如果是这样,您可能希望显示另一个组件,如加载栏/微调器/等,以向用户提供一些反馈.您的reducer可以将此bool默认为true,然后将其设置为false LOGGED_IN.您的减速器可能看起来像这样:

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;
  }
}
Run Code Online (Sandbox Code Playgroud)

然后在render()您的HOC中LoadingComponent,如果isAuthenticating为真,则可以返回a 而不是null .

这非常类似于我们刚刚在此PR中添加到redux-auth-wrapper的功能 - https://github.com/mjrussell/redux-auth-wrapper/pull/35如果您想将其用于更多参考