Redux 导致无限刷新循环

时间:2021-02-24 03:41:55

标签: reactjs loops redux refresh

我对 Redux 还很陌生,但我正在尝试将它添加到我现有的项目中,并且正在无限刷新循环回到我的 /login 页面。我没有看到即时错误,也找不到问题可能来自哪里。我认为循环可能来自 App.js 中的渲染,它拉入了 Login 组件,但似乎无法确定它。我非常感谢您对此的任何帮助!

App.js:

import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import './App.css';
import MuiThemeProvider from '@material-ui/core/styles/MuiThemeProvider';
import createMuiTheme from '@material-ui/core/styles/createMuiTheme';
import themeFile from './util/theme';
import jwtDecode from 'jwt-decode';

// Redux
import { Provider } from 'react-redux';
import store from './redux/store';


// Components
import Navbar from './components/Navbar';
import AuthRoute from './util/AuthRoute';

// Pages
import home from './pages/home';
import login from './pages/login';
import signup from './pages/signup';


const theme = createMuiTheme(themeFile);

let authenticated;
const token = localStorage.FBIdToken;

if(token){
  const decodedToken = jwtDecode(token);
  if(decodedToken.exp * 1000 < Date.now()){
    window.location.href='/login'
    authenticated = false;
  } else {
    authenticated = true;
  };
}

class App extends Component {
  render() {
  return (
    <MuiThemeProvider theme={theme}>
    <Provider store={store}>
      <Router>
      <Navbar/>
        <div className="container">
        <Switch>
          <Route exact path="/" component={home}/>
          <AuthRoute exact path="/login" component={login} authenticated={authenticated}/>
          <AuthRoute exact path="/signup" component={signup} authenticated={authenticated}/>
        </Switch>
        </div>
        </Router>
    </Provider>
    </MuiThemeProvider>
  );
}
}

export default App;

登录页面:

import React, { Component } from 'react'
import withStyles from '@material-ui/core/styles/withStyles'
import PropTypes from 'prop-types'
import AppIcon from '../images/micrologo.png'
import { Link } from 'react-router-dom'

//MUI Stuff
import Grid from '@material-ui/core/Grid';
import Typography from '@material-ui/core/Typography'
import TextField from '@material-ui/core/TextField'
import Button from '@material-ui/core/Button'
import CircularProgress from '@material-ui/core/CircularProgress'

//Redux stuff
import { connect } from 'react-redux';
import { loginUser } from '../redux/actions/userActions';

const styles = (theme) => ({
    ...theme.spreadThis
})


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

    componentWillReceiveProps(nextProps){
       if(nextProps.UI.errors){
           this.setState({ errors: nextProps.UI.errors })
       }
    }

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

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

    render() {
        const { classes, UI: { loading } } = this.props;
        const { errors } = this.state;

        return (
            <Grid container className={classes.form}>
                <Grid item sm/>
                <Grid item sm>
                    <img src={AppIcon} alt="micrologo" className={classes.image}/>
                    <Typography variant="h3" className={classes.pageTitle}>
                        Login
                    </Typography>
                    <form noValidate onSubmit={this.handleSubmit}>
                        <TextField 
                        id="email" 
                        name="email" 
                        type="email" 
                        label="Email" 
                        className={classes.textField}
                        helperText={errors.email}
                        error={errors.email ? true : false}
                        value={this.state.email} 
                        onChange={this.handleChange} 
                        fullWidth 
                        />
                     <TextField 
                        id="password" 
                        name="password" 
                        type="password" 
                        label="Password" 
                        className={classes.textField}
                        helperText={errors.password}
                        error={errors.password ? true : false}
                        value={this.state.password} 
                        onChange={this.handleChange} 
                        fullWidth 
                        />
                    {errors.general && (
                        <Typography variant="body2" className={classes.customError}>
                            {errors.general}
                        </Typography>
                    )}
                    <Button 
                    type="submit" 
                    variant="contained" 
                    color="primary" 
                    className={classes.button}
                    disabled={loading}
                    >
                        Login
                        {loading && (
                            <CircularProgress size={30} className={classes.progress}/>
                        )}
                    </Button>
                    <br />
                    <small>Don't have an account? Sign up <Link to="/signup">here</Link>
                    </small>
                    </form>
                </Grid>
                <Grid item sm/>
            </Grid>
        )
    }
}

login.propTypes = {
    classes: PropTypes.object.isRequired,
    loginUser: PropTypes.func.isRequired,
    user: PropTypes.object.isRequired,
    UI: PropTypes.object.isRequired
};

const mapStateToProps = (state) => ({
    user: state.user,
    UI: state.UI
});

const mapActionsToProps = {
    loginUser
}

export default connect(mapStateToProps, mapActionsToProps)(withStyles(styles)(login));

用户详细信息:

import { SET_USER, SET_ERRORS, CLEAR_ERRORS, LOADING_UI } from '../type';
import axios from 'axios'

export const loginUser = (userData, history) => (dispatch) => {
    dispatch({ type: LOADING_UI}); 
    axios
    .post('/login', userData)
    .then((res) => {
        const FBIdToken = `Bearer ${res.data.token}`;
        localStorage.setItem('FBIdToken', FBIdToken);
        axios.defaults.headers.common['Authorization'] = FBIdToken;
        dispatch(getUserData());
        dispatch({ type: CLEAR_ERRORS });
        history.push('/');
    })
    .catch((err) => {
       dispatch({ 
           type: SET_ERRORS,
           payload: err.response.data
       })
    })
}

export const getUserData = () => (dispatch) => {
    axios.get('/user')
        .then((res) => {
            dispatch({
                type: SET_USER,
                payload: res.data
            })
        })
        .catch((err) => 
            console.log(err)
        )
}

编辑:对引用我的 User Reducer 的 User Actions 文件进行更改后,是否可能与 User Reducer 代码有关?

import { SET_USER, SET_ERRORS, CLEAR_ERRORS, LOADING_UI, SET_AUTHENTICATED, SET_UNAUTHENTICATED } from '../type';

const initialState = {
    authenticated: false,
    credentials: {},
    likes: [],
    notifications: []
};

export default function(state = initialState, action){
    switch(action.type){
        case SET_AUTHENTICATED:
            return {
                ...state,
                authenticated: true
            };
        case SET_UNAUTHENTICATED:
            return initialState
        case SET_USER:
            return {
                authenticated: true,
                ...action.payload
            };
        default:
            return state;
    }
}

编辑 2:添加副本 > 从网络选项卡复制提取代码:

fetch("http://localhost:3000/login", {
  "headers": {
    "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
    "accept-language": "en-US,en;q=0.9",
    "if-none-match": "W/\"717-3FVndTj2FHm3TgZjXTrLARSY62Q\"",
    "sec-fetch-dest": "document",
    "sec-fetch-mode": "navigate",
    "sec-fetch-site": "same-origin",
    "upgrade-insecure-requests": "1"
  },
  "referrer": "http://localhost:3000/login",
  "referrerPolicy": "strict-origin-when-cross-origin",
  "body": null,
  "method": "GET",
  "mode": "cors",
  "credentials": "omit"
});

1 个答案:

答案 0 :(得分:0)

您可以尝试以下操作:

export const loginUser = (userData, history) => (
  dispatch
) => {
  dispatch({ type: LOADING_UI });
  axios
    .post("/login", userData)
    .then((res) => {
      const FBIdToken = `Bearer ${res.data.token}`;
      localStorage.setItem("FBIdToken", FBIdToken);
      axios.defaults.headers.common[
        "Authorization"
      ] = FBIdToken;
      //wait for getUserData to finish
      return getUserData()(dispatch);
    })
    .then(() => {
      //getUserData is finished
      dispatch({ type: CLEAR_ERRORS });
      history.push("/");
    })
    .catch((err) => {
      dispatch({
        type: SET_ERRORS,
        payload: err.response.data,
      });
    });
};

export const getUserData = () => (dispatch) => {
  //return a promise so loginUser action can wait for
  //  it to finish
  return axios.get("/user").then((res) => {
    dispatch({
      type: SET_USER,
      payload: res.data,
    });
  });
  //if you catch it then the catch that set errors is
  //  pointless
  // .catch((err) => console.log(err));
};
相关问题