如何在React-Redux中安装后将状态更改回false

时间:2017-11-03 16:14:10

标签: reactjs react-redux

所以我将我的受保护路由包含在HOC中,首先通过查看是否有令牌来检查该人是否经过身份验证。如果他们有令牌,则将其发送到服务器以查看它是否有效。如果有效,则刷新(如果它<15分钟)。在此过程中,如果令牌有效,则PERMIT_RENDER的状态设置为true,允许组件呈现(如果是);如果没有,它只是一个加载屏幕,直到服务器响应。希望在下面的代码中清楚这一点。

无论如何,使用我当前的设置,当您第一次登录时,它会带您到/home这是一条受保护的路线。您可以单击.nav中的链接以在其他受保护路由之间切换。首次登录时问题是permitRender正常工作并显示加载,直到服务器响应并将您带到/home。此时似乎permitRender应该回到false,这样当您点击指向受保护路由的链接时,它就不会加载,直到服务器响应并且用户刚刚获得加载屏幕直到那时。但是,permitRender一旦true保持这种状态,除非您刷新屏幕。此外,它会在收到服务器响应之前自动导航到其他受保护的路由。

基本上,在挂载或更新后将permitRender设置回false的正确方法是什么,这样每次有人导航到受保护路由时都会触发我的加载组件?

对我来说似乎很直观的一些事情(请注意,你不知道React和hwo在setStatecomponentDidMount()componentDidUpdate()中使用componentDidMount(...state)等等。 :

this.setState(this.state.auth.permitRender = false);

结果为cannot read property 'auth' of null

// ./helpers/require_auth.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { authRequired, refreshToken } from '../actions/authentication';
import Loading from './loading';

// This HOC not only protects certain routes by checking for existence of a token,
// but if the token exists it make sure it is current
// if it is current, it will refresh the token
export default function(ComposedComponent) {
    class AuthenticationRequired extends Component {

        // Check if the user has a token when protected route component is about to mount
        // Route them to / if they do not
        componentWillMount() {
            if (!sessionStorage.getItem('token')) {
                this.props.authRequired();
            } else {
                this.props.refreshToken();
            }
        }

        // If the component will be updated then also check if user is authorized
        componentWillUpdate() {
            if (!sessionStorage.getItem('token')) {
                this.props.authRequired();
            } else {
                this.props.refreshToken();
            }
        }

        // Render the component if passing these checks
        render() {
            if (this.props.permitRender) {
                return <ComposedComponent {...this.props} />            
            } else if (!this.props.permitRender) {
                return <Loading />
            }
        }
    }

    // 
    function mapStateToProps(state) {
        return { 
            permitRender: state.auth.permitRender
        };
    }

    // Conenct to the authRequired action
    return connect(mapStateToProps, { authRequired, refreshToken })(AuthenticationRequired);
}
// ./actions/authentication
import axios from 'axios';
import { push } from 'react-router-redux';
import { ROOT_URL } from '../../config/config.json';

// Establish the different types
export const AUTH_USER = 'auth_user';
export const UNAUTH_USER = 'unauth_user';
export const PERMIT_RENDER = 'permit_render';

// Refresh the token based on the users activity
export function refreshToken() {
    return function(dispatch) {
        axios
            .post(
                `${ROOT_URL}/api/auth/refresh/`, 
                { 'token': sessionStorage.getItem('token') }, 
                { headers: { 
                    'Content-Type': 'application/json',
                }
            })
            .then(response => {
                sessionStorage.setItem('token', response.data.token);
                dispatch({ type: AUTH_USER });
                dispatch({ type: PERMIT_RENDER });
            })
            .catch(error => {
                sessionStorage.clear();
                dispatch({ type: UNAUTH_USER });  
                dispatch(push('/'));
                dispatch(authError('This session has expired. Please login to continue browsing.')); 
            });            
    }
}
// ./reducers/authentication.js
import {
    AUTH_USER,
    UNAUTH_USER,
    PERMIT_RENDER,
} from '../actions/authentication';

export default function(state = {}, action) {
    switch(action.type) {
        case AUTH_USER:
            return { ...state, error: '', authenticated: true };
        case UNAUTH_USER:
            return { ...state, authenticated: false };
        case PERMIT_RENDER:
            return { ...state, permitRender: true };
        default:
            return state;
    }

    return state;
}
// ./reducers/index.js
import { combineReducers } from 'redux';
import { reducer as form } from 'redux-form';
import { routerReducer } from 'react-router-redux';
import authReducer from './authentication';
import helpReducer from './help';

const rootReducer = combineReducers({
    form,
    router: routerReducer,
    auth: authReducer,
    help: helpReducer
});

export default rootReducer;

1 个答案:

答案 0 :(得分:0)

查看yuantonito在此分享的帖子:

In terms of a stateless front-end client, how secure is this JWT logic?

我想到我可以做到以下几点:

// ./require_auth.js
import { unpermitRender } from '..actions/'

....
componentWillUnmount() {
    this.props.unpermitRender();
}
....
// ./actions/authentication.js
export function unpermitRender() {
    return function(dispatch) {
        dispatch({ 
            type: PERMIT_RENDER,
            payload: false
        });         
    };
}

然后我修改了./actions/authentication.js中正在使用的其他地方:

dispatch({ type: PERMIT_RENDER })

要:

dispatch({ type: PERMIT_RENDER, payload: true }) // or false

这意味着我必须将reducer修改为:

// ./reducers/authentication.js
...
case PERMIT_RENDER:
    return { ...state, permitRender: action.payload };
...

现在我正在加载屏幕在受保护的路由之间导航,并且仅在收到服务器响应时才进行渲染。