反应无法通过withAuth HOC访问的更新上下文

时间:2020-04-25 07:37:44

标签: javascript reactjs use-reducer use-context

我正在使用useContext,useReducer和用于对路由进行身份验证的高阶组件(HOC)来对React项目进行身份验证。

我面临的挑战是,登录后,HOC会重定向到登录页面,因为即使在进入HOC之前将其设置为true,未认证也会返回false。

withAuth 我用来检查用户是否已通过身份验证并被允许访问某些路由的HOC

import React from 'react';
import { Redirect } from 'react-router-dom';
import { verifyRole } from '../../helpers/auth.helpers';
import withUser from '../WithUser';

const withAuth = (...permittedRoles) => (ComposedComponent) => {
  const Authorization = (props) => {

    const { isAuthenticated } = props;

    if (!isAuthenticated) return <Redirect to='/signin' />;

    if (!verifyRole(...permittedRoles)) {
      return <Redirect to='/' />;
    }
    return <ComposedComponent {...props} permittedRoles={permittedRoles} />;
  };
  return withUser(Authorization);
};

export default withAuth;

withUser 提供要使用的上下文状态的HOC

import React from 'react';
import { UserContext } from '../../context/userContext';

const withUser = (ComposedComponent) => (props) => (
  <UserContext.Consumer>
    {(user) => <ComposedComponent {...props} {...user} />}
  </UserContext.Consumer>
);
export default withUser;

authReducer 我用于更新上下文的reducer

import {
  SIGNIN_START,
  SIGNIN_FAILURE,
  SIGNIN_SUCCESS,
} from '../actions/actionTypes';

const authReducer = (state, action) => {
  switch (action.type) {
  case SIGNIN_START:
    return { ...state, isLoading: true, isAuthenticated: false, errorMsg: null };
  case SIGNIN_SUCCESS:
    return {
      ...state,
      isLoading: false,
      response: action.payload,
      errorMsg: null,
      isAuthenticated: true,
    };
  case SIGNIN_FAILURE:
    return {
      ...state,
      isLoading: false,
      response: action.payload.response,
      errorMsg: action.payload.response
        ? action.payload.response.data.message
        : 'Sorry, there was an error, please try again',
      isAuthenticated: false,
    };
  default:
    return state;
  }
};

export default authReducer;

操作 身份验证操作

import { SIGNIN_START, SIGNIN_FAILURE, SIGNIN_SUCCESS } from './actionTypes';

const signinStart = () => ({
  type: SIGNIN_START,
});

const signinSuccess = (payload) => ({
  type: SIGNIN_SUCCESS,
  payload,
});

const signinFailure = (payload) => ({
  type: SIGNIN_FAILURE,
  payload,
});

export const signin = (dispatch) => {
  dispatch(signinSuccess())
}
const signinUser = async (dispatch, userObject) => {
  dispatch(signinStart());
  try {
    const user = await Axios.post(`${process.env.REACT_APP_BASE_API_URL}/auth/signin`, {
      ...userObject,
    });

    if (user) {
      const { token } = user.data;
      localStorage.setItem('token', token);
      dispatch(signinSuccess(token));
      return true;
    }
  } catch (error) {
    dispatch(signinFailure(error));
  }
};

export default signinUser;

SigninComponent

import React, { useState, useContext } from 'react';
import swal from 'sweetalert';
import ClipLoader from 'react-spinners/ClipLoader';

import FormStyles from '../../styles/FormStyles.module.scss';
import SigninStyles from './Signin.module.scss';
import { UserContext } from '../../context/userContext';
import signinUser from '../../actions/auth.action';

export const Signin = ({history}) => {
  const initialState = {
    username: '',
    password: '',
  };

  const [signinState, setSigninState] = useState(initialState);

  const { dispatch, errorMsg, isLoading } = useContext(UserContext);
  const { username, password } = signinState;

  const handleInputChange = (event) => {
    setSigninState({
      ...signinState,
      [event.target.name]: event.target.value,
    });
  };

  const handleSignin = (e) => {
    e.preventDefault();
    const signinResult = signinUser(dispatch, { username, password });
    if(signinResult)  history.push('/');

    if(errorMsg) {
      swal('Oops!!!', errorMsg, 'error');
    }
  };

  return (
    <div className={SigninStyles.formContainer}>
      <h2 className={`${FormStyles['form-title']} container`}>Signin</h2>
      <form className={SigninStyles.formBody} onSubmit={handleSignin}>
        <p className={FormStyles['input-group']}>
          <label htmlFor='username'>Username</label>
          <input
            type='text'
            name='username'
            id='username'
            placeholder='Username'
            onChange={handleInputChange}
            value={username}
            required
          />
        </p>
        <p className={FormStyles['input-group']}>
          <label htmlFor='password'>Password</label>
          <input
            type='password'
            name='password'
            id='password'
            placeholder='password'
            onChange={handleInputChange}
            value={password}
            required
          />
        </p>
        <p className={FormStyles['btn-group']}>
          <button
            className={`${FormStyles['btn']} ${FormStyles['btn-maroon']}`}
          >
            {!isLoading && 'Add user'}
            <ClipLoader loading={isLoading} size='30px' color='#fff' />
          </button>
          <a href='/forgot-password' className={FormStyles['forgot-password']}>
            Forgot password?
          </a>
        </p>
      </form>
    </div>
  );
};

export default Signin;

0 个答案:

没有答案