簡體   English   中英

Axios請求不適用於React + Redux

[英]Axios request not working with React + Redux

我將嘗試給出一個前提,然后再編寫代碼。

我決定將Material UI實施到我的React項目中,並且大部分工作都在進行中。 如何設置應用程序,用戶將面臨“登錄”頁面。 Login.js模塊呈現SignIn.js模塊 ,輸入其憑據,然后單擊提交。 formDataonChangeonSubmit作為道具從Login組件傳遞到SignIn組件-並且Login組件通過mapStateToProps接收它們。 Login組件使用connect中間件將redux狀態鏈接到react應用。

單擊提交觸發formData(在Login組件中,傳遞到SignIn組件中)擊中位於"../../actions/auth"; login方法"../../actions/auth"; 錯誤是從該方法內部發生的,在try catch中的axios調用處,在此我嘗試與后端const response = await axios.post("/api/auth", body, config);

奇怪的是那個dispatch({ type: LOGIN_SUCCESS, payload: response.data }); 從不被命中,這應該將狀態設置為從后端返回的令牌,因為似乎從未執行LOGIN_SUCCESS 但是非常奇怪的是,控制台記錄令牌的實際工作原理! 似乎它從未存儲過,從而迫使AUTH_ERROR被調用。

這是我的登錄組件:

 // Login.js
 import SignIn from "../../material/SignIn";

 const Login = ({ setAlert, login, isAuthenticated }) => {
 const [formData, setFormData] = useState({
 email: "",
 password: ""
 });

 const { email, password } = formData;

 const onChange = e => {
 setFormData({ ...formData, [e.target.name]: e.target.value });
 };

 const onSubmit = e => {
 login(email, password);
 };
 // Redirect if logged in
 if (isAuthenticated) {
 return <Redirect to="/dashboard" />;
 }

 return (
 <Fragment>
      <SignIn
      email={email}
      password={password}
      onSubmit={onSubmit}
      onChange={onChange}
      isAuthenticated={isAuthenticated}
      />
 </Fragment>
 );
 };

 Login.propTypes = {
 setAlert: PropTypes.func.isRequired,
 login: PropTypes.func.isRequired,
 isAuthenticated: PropTypes.bool
 };

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

 export default connect(
 mapStateToProps,
 { setAlert, login }
 )(Login);

它正在呈現的SignIn組件在這里:

 // SignIn.js
 export default function SignIn({ email, password, onChange, onSubmit }) {
 const classes = useStyles();

 return (
 <Container component="main" maxWidth="xs">
      <CssBaseline />
      <div className={classes.paper}>
      <Avatar className={classes.avatar}>
           <LockOutlinedIcon />
      </Avatar>
      <Typography component="h1" variant="h5">
           Sign in
      </Typography>
      <form onSubmit={e => onSubmit(e)} className={classes.form} noValidate>
           <TextField
           variant="outlined"
           margin="normal"
           required
           onChange={e => onChange(e)}
           fullWidth
           id="email"
           label="Email Address"
           name="email"
           value={email}
           // autoComplete="email"
           autoFocus
           />
           <TextField
           variant="outlined"
           margin="normal"
           required
           onChange={e => onChange(e)}
           fullWidth
           name="password"
           label="Password"
           type="password"
           value={password}
           id="password"
           autoComplete="current-password"
           />
           <FormControlLabel
           control={<Checkbox value="remember" color="primary" />}
           label="Remember me"
           />
           <Button
           type="submit"
           fullWidth
           variant="contained"
           color="primary"
           className={classes.submit}
           >
           Sign In
           </Button>
           <Grid container>
           <Grid item xs>
           <Link href="#" variant="body2">
                Forgot password?
           </Link>
           </Grid>
           <Grid item>
           <Link href="#" variant="body2">
                {"Don't have an account? Sign Up"}
           </Link>
           </Grid>
           </Grid>
      </form>
      </div>
      <Box mt={5}>
      <MadeWithLove />
      </Box>
 </Container>
 );
 }

單擊提交按鈕將在我的登錄組件中引發onSubmit方法:

 // Login user
 export const login = (email, password) => async dispatch => {
 // Config needed because we're sending data
 const config = {
 headers: {
      "Content-Type": "application/json"
 }
 };

 const body = JSON.stringify({ email, password });

 try {
 const response = await axios.post("/api/auth", body, config);

 // Skips over this dispatch
 dispatch({
      type: LOGIN_SUCCESS,
      payload: response.data
 });

 // But hits this dispatch.. and then console logs 'REACHED' as seen below
 dispatch(loadUser());
 } catch (err) {
 const errors = err.response.data.errors;

 if (errors) {
      errors.forEach(error => {
      dispatch(setAlert(error.msg, "danger"));
      });
 }

 dispatch({
      type: LOGIN_FAIL
 });
 }
 };

如果您注意到在axios調用之后, loadUser is called ,定義為:

 // Load user
 export const loadUser = () => async dispatch => {
 const token = localStorage.token;

 console.log('REACHED!'); // reached

 if (token) {
 setAuthToken(token);
 }

 try {
 const response = await axios.get("/api/auth");

 dispatch({
      type: USER_LOADED,
      payload: response.data
 });
 } catch (err) {
 dispatch({
      type: AUTH_ERROR // This is dispatched
 });
 }
 };

后端路由如下:

 // @route  POST api/auth
 // @desc   Authenticate user and get token
 // @access Public
 router.post(
 "/",
 [
 check("email", "Please include a valid email").isEmail(),
 check("password", "Please is required").exists()
 ],
 async (req, res) => {
 const errors = validationResult(req);

 // send back any errors
 if (!errors.isEmpty()) {
      return res.status(400).json({
      errors: errors.array()
      });
 }

 const { email, password } = req.body;

 try {
      // check if user exists, send error if so
      let user = await User.findOne({ email });

      if (!user) {
      return res
           .status(400)
           .json({ errors: [{ msg: "Invalid credentials" }] });
      }

      const isMatch = await bcrypt.compare(password, user.password);

      if (!isMatch) {
      return res
           .status(400)
           .json({ errors: [{ msg: "Invalid credentials" }] });
      }
      // return jsonwebtoken so that way they're logged in right
      // away, without having to log in after registering
      const payload = {
      user: {
           id: user.id
      }
      };

      jwt.sign(
      payload,
      config.get("jwtSecret"),
      {
           expiresIn: process.env.PORT ? 3600 : 36000
      },
      (err, token) => {
           if (err) throw err;

           console.log(token); // prints token!

           return res.json({ token });
      }
      );
 } catch (err) {
      console.log(err);
      res.status(500).send("Server error");
 }
 }
 );

我現在很困惑。 令牌正在被渲染,但似乎React在Node有機會將其發送回之前並未“等待”響應。

不知道如何解釋這一點,但我通過擺脫form標記的onSubmit觸發器並將其放在SignIn.js中來解決了。 我將按鈕的類型也更改為鍵入按鈕。 得到它的工作:)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM