代码之家  ›  专栏  ›  技术社区  ›  Saurabh Mistry

React应用程序登录错误:超过最大更新深度

  •  0
  • Saurabh Mistry  · 技术社区  · 7 年前

    我正在使用react和redux构建带有后端passport jwt的登录验证系统。

    PrivateRoute 到某些需要身份验证的路由。

    我遇到的错误:

    enter image description here enter image description here

    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;
        }
    }
    

    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)
    

    privaterout.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;
    

    2 回复  |  直到 7 年前
        1
  •  1
  •   Saurabh Mistry    7 年前

    我通过替换 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);
    
        2
  •  0
  •   Mohammad Rajabloo    7 年前

    我建议您使用另一个状态变量来保存请求状态。喜欢 loggingIn 如果是真的,显示加载如果是假的和 isAuthenticated 如果为false,则不会请求用户登录,也不会登录。所以把它重定向到 /login

    privaterout.js组件

    import React from 'react';
    import {Route,Redirect} from 'react-router-dom';
    
    class PrivateRoute extends Component {
    render() {
        const {
            component: Component, loggingIn, isAuthenticated, ...rest
        } = this.props;
        if (loggingIn) {
            return (
                <div>
                    Please wait.
                </div>
            );
        }
        return (<Route {...rest} render={props => (isAuthenticated ? (<Component {...props} />) : (<Redirect to={{ pathname: '/login', state: { from: props.location } }} />))} />);
    }}
    export default 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=>{
        dispatch(loggingIn(true));
        axios.post('/api/auth/login',userdata)
             .then(res=>{
                 dispatch(loggingIn(false));
                 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(loggingIn(false));
                 dispatch({type:GET_ERRORS,payload:err.response.data});
             })
    }
    
    // Set logged in user
    export const setCurrentUser = decoded => {
        return {
          type: SET_CURRENT_USER,
          payload: decoded
        };
      };
    
    export const loggingIn = status => {
        return {
            type: 'LOGGINGIN',
            status,
        }
    }
    

    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: {}
            };
            case 'LOGGINGIN':
                return {
                    ...state,
                    loggingIn: action.status,
                };
            default:
            return state;
        }
    }
    

    记住传球 登录

    :演示如何在App.js中使用

    应用程序.js

    import React, { Component } from 'react';
    import {BrowserRouter as Router,Route,Switch} from 'react-router-dom';
    import {connect} from 'react-redux';
    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';
    
    
    class App extends Component {
      constructor(props){
        super(props);
        const { dispatch } = props;
        if(localStorage.jwtToken){
            setAuthToken(localStorage.jwtToken);
            // Decode token and get user info and exp
            const decoded = jwt_decode(localStorage.jwtToken);
            dispatch(setCurrentUser(decoded));
            // Check for expired token
            const currentTime = Date.now() / 1000;
            if (decoded.exp < currentTime) {
               // Logout user
              dispatch(logoutUser());
              // Clear current Profile
              //dispatch(clearCurrentProfile());
              // Redirect to login
              window.location.href = '/login';
           }
        }
      }
    
      render() {
        const { isAuthenticated, loggingIn } = this.props;
        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 loggingIn={loggingIn} isAuthenticated={isAuthenticated} exact path="/dashboard" component={Dashboard}/>
    
            <Route component={NotFound404} />
            </Switch>
            </div>
            <Footer/>
          </div>
    
          </Router>
          </Provider>
        );
      }
    }
    const mapStateToProps = state = {
       const { loggingIn, isAuthenticated } = state.auth;
       return { loggingIn, isAuthenticated }
    }
    export default connect(mapStateToProps)(App);
    
    推荐文章