首页 > 解决方案 > React App登录错误:超过最大更新深度

问题描述

我正在使用 react with redux 来构建带有后端护照 jwt 的登录身份验证系统。

登录之前工作正常,我已将PrivateRoute添加到一些需要身份验证的路由。

我得到的错误:

在此处输入图像描述 在此处输入图像描述

src/actions/authActions.js

import { GET_ERRORS,CLEAR_ERRORS,SET_CURRENT_USER,LOGOUT_USER} from './types';
import axios from 'axios';
import setAuthToken from '../utils/setAuthToken';
import jwt_decode from 'jwt-decode';

export const loginUser= userdata =>dispatch=>{
    axios.post('/api/auth/login',userdata)
         .then(res=>{
             console.log('loginUser action response ==>',res.data);
             const {token}=res.data;
             localStorage.setItem('jwtToken',token);
             setAuthToken(token); 
             // Decode token to get user data
             const decoded = jwt_decode(token);
             dispatch(setCurrentUser(decoded));
         }).catch(err=>{
             dispatch({type:GET_ERRORS,payload:err.response.data});
         })
}

// Set logged in user
export const setCurrentUser = decoded => {
    return {
      type: SET_CURRENT_USER,
      payload: decoded
    };
  };

src/reducers/authReducers.js

import isEmpty from '../validation/is-empty';
import { SET_CURRENT_USER,LOGIN_USER,LOGOUT_USER} from '../actions/types';

const initialState = {
    isAuthenticated: false,
    user: {}
  };

  export default function(state = initialState, action) {
    switch (action.type) {

        case LOGIN_USER:
        case SET_CURRENT_USER:
            return {
                ...state,
                isAuthenticated: !isEmpty(action.payload),
                user: action.payload
            };

        case LOGOUT_USER:
        return {
            ...state,
            isAuthenticated:false,
            user: {}
        };

        default:
        return state;
    }
}

应用程序.js

import React, { Component } from 'react';
import {BrowserRouter as Router,Route,Switch} from 'react-router-dom';
import {Provider} from 'react-redux';
import store from './store';
import Footer from './partials/footer';
import Header from './partials/header';

import Login from './components/auth/login';
import { setCurrentUser ,logoutUser} from './actions/authActions';
import  jwt_decode  from 'jwt-decode';
import setAuthToken from './utils/setAuthToken';
import PrivateRoute from './utils/PrivateRoute';
import Dashboard from './components/user/dashboard';
import NotFound404 from './components/error/404';

if(localStorage.jwtToken){
  setAuthToken(localStorage.jwtToken);
  // Decode token and get user info and exp
  const decoded = jwt_decode(localStorage.jwtToken);
  store.dispatch(setCurrentUser(decoded));
    // Check for expired token
    const currentTime = Date.now() / 1000;
    if (decoded.exp < currentTime) {
      // Logout user
      store.dispatch(logoutUser());
      // Clear current Profile
      //store.dispatch(clearCurrentProfile());
      // Redirect to login
      window.location.href = '/login';
    }
}

export default class App extends Component {
  constructor(){
    super();
    this.state={
      isAuthenticated:store.getState().auth.isAuthenticated
    }
  }

  render() {
    return ( 
      <Provider store={store}>
      <Router>

      <div className="App">
        <Header/>
        <div className="container">
        <Switch>
        <Route exact path="/" component={Home}/>
        <Route exact path="/login" component={Login} />

        <PrivateRoute isAuthenticated={this.state.isAuthenticated} exact path="/dashboard" component={Dashboard}/>

        <Route component={NotFound404} />
        </Switch>
        </div>
        <Footer/>
      </div>

      </Router>
      </Provider>
    );
  }
}

src/components/login.js

import React, { Component } from 'react'
import { Link } from 'react-router-dom';
import classnames from 'classnames';
import { connect } from 'react-redux';
import { loginUser } from '../../actions/authActions';
import { PropTypes } from 'prop-types';

class Login extends Component {
    constructor(){
        super();
        this.state={
            email:'',
            password:'',
            errors:{}
        }
        this.handleChange=this.handleChange.bind(this);
        this.handleSubmit=this.handleSubmit.bind(this);
    }

    handleChange(event){
        this.setState({
            [event.target.name]:event.target.value
        });
    }

    handleSubmit(event){
        event.preventDefault();
        const user={
            email:this.state.email,
            password:this.state.password
        }
        this.props.loginUser(user);
    }


    componentDidMount() {
        if (this.props.auth.isAuthenticated) {
        this.props.history.push('/dashboard');
        }
    }

    componentWillReceiveProps(nextProps){

        if(nextProps.errors){
            this.setState({
                errors:nextProps.errors 
            });
        }

        if(nextProps.auth.isAuthenticated){
            this.props.history.push('/dashboard');
        }
    }

    render () {
        const {errors} = this.state;
        return (
            <div className="row my-5">
            <div className="col-md-4 offset-md-4 col-sm-12">
            <div className="card shadow-sm">
            <h5 className="card-header">Login</h5>
            <div className="card-body">
                <form onSubmit={this.handleSubmit}>
                    <div className="form-group">
                    <label htmlFor="email" className="label">Email</label>
                    <input type="email" id="email" name="email"  value={this.state.email} onChange={this.handleChange} className={classnames('form-control',{'is-invalid':errors.email})}/>
                    {errors.email && (<div className="invalid-feedback">{errors.email}</div>)}

                    </div>

                    <div className="form-group">
                    <label htmlFor="password" className="label">Password</label>
                    <input type="password" id="password" name="password"  value={this.state.password} onChange={this.handleChange}  className={classnames('form-control',{'is-invalid':errors.password})}/>
                    {errors.password && (<div className="invalid-feedback">{errors.password}</div>)}

                    </div>

                    <button type="submit" className="btn btn-success btn-block">Login</button>

                </form>
                <div className="py-3 border-bottom"></div>
                <Link to="/register" className="btn btn-default btn-block my-2">Haven't created account yet ?</Link>
                <Link to="/forgotpassword" className="btn btn-default btn-block">Forgot Password ?</Link>
            </div>
          </div>
            </div>
            </div>

        )
    }
}

const mapStateToProps = (state, ownProps) => ({
    auth:state.auth,
    errors:state.errors
})

const mapDispatchToProps = {
    loginUser
}

Login.propTypes={
    auth:PropTypes.object.isRequired,
    errors:PropTypes.object.isRequired, 
    loginUser:PropTypes.func.isRequired
}


export default connect(mapStateToProps,mapDispatchToProps)(Login)

PrivateRoute.js 组件

import React from 'react';
import {Route,Redirect} from 'react-router-dom';

const PrivateRoute=({component: Component, isAuthenticated, ...rest}) => {
    return (
        <Route
          {...rest}
          render={(props) => isAuthenticated === true
            ? <Component {...props} />
            : <Redirect to={{pathname: '/login', state: {from: props.location}}} />}
        />
      )
}
export default PrivateRoute;

请帮我解决这个错误。

标签: reactjsreact-reduxreact-router

解决方案


我通过替换PrivateRoute组件解决了我的错误,如下所示:

import React from 'react';
import { Route, Redirect } from 'react-router-dom';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';

const PrivateRoute = ({ component: Component,auth, ...rest }) => (
  <Route
    {...rest}
    render={props =>
      auth.isAuthenticated === true ? (
        <Component {...props} />
      ) : (
        <Redirect to="/login" />
      )
    }
  />
);

PrivateRoute.propTypes = {
  auth: PropTypes.object.isRequired
};

const mapStateToProps = state => ({
  auth: state.auth
});

export default connect(mapStateToProps)(PrivateRoute);

推荐阅读