开发者问题收集

无法使用从 Axios 收到的数据在 React Hooks 中设置状态

2020-07-29
1209

我正在使用 React Hooks 创建登录表单并使用 Axios 查询后端。成功登录后,我将重定向到正常运行的主页。问题在于尝试失败时,我想将 loginFailed 设置为 true,并基于此对表单进行条件渲染。 但不幸的是 setLoginFailed 不起作用。

这是我在客户端执行的操作:

import React, { useState } from "react"
import { useForm } from "react-hook-form"
import { useHistory } from "react-router-dom";
import { yupResolver } from '@hookform/resolvers'
import * as yup from "yup"
import axios from 'axios'
import './Login.css'

const schema = yup.object().shape({
  username: yup.string().required("Please enter Username."),
  password: yup.string().required("Please enter Password.")
})

export default function Login() {

  const [loginFailed, setLoginFailed] = useState(null);

  const { register, handleSubmit, errors } = useForm({
    resolver: yupResolver(schema)
  })

  const history = useHistory();

  const onSubmit = data => {
    axios.post('/login', data)
    .then((response) => {
      if (response.data.success) {
        history.push("/")
      } else {
        setLoginFailed(true)
      }
    })
  }

  return (
     
    <form className="login-form" onSubmit={handleSubmit(onSubmit)}>
      
      {loginFailed && <p>Invalid Username/Password.</p>}

      <input type="text" name="mobile" placeholder="Mobile Number" ref={register} />
      <p className="error">{errors.mobile?.message}</p>
        
      <input type="password" name="password" placeholder="Password" ref={register} />
      <p className="error">{errors.password?.message}</p>
      
      <input type="submit" value="Login" />
    </form>
  )
}

以及在服务器端执行的操作:

var express = require('express')
var router = express.Router()
var passport = require('passport')
var Farmer = require('../models/farmer')


router.post('/login', function(req, res, next) {
  console.log(req.body)
  passport.authenticate('local', function(err, user, info) {
    if (err) { 
      return res.json({success: false}) 
    }
    if (!user) { 
      return res.json({success: false}) 
    }
    req.logIn(user, function(err) {
      if (err) { 
        return res.json({success: false}) 
      }
      return res.json({success: true})
    })
  })(req, res, next)
})

module.exports = router


我做错了什么?如何在客户端正确设置我的状态?

2个回答

我在本地重新创建了您的应用,一切看起来都很好,除了您用于“手机号码”输入的名称。在您的 yup 架构中,您有 username ,而输入的名称是 mobile 。因此,您必须将其中一个更改为另一个。

在我的示例中,这意味着 yup 认为提交无效,并且从未向 API 提交任何内容。除非问题中的代码与您的实际代码不同,否则 onSubmit 永远不会发生。我很好奇您的代码是如何进入 axios.then 的。

无论如何,这是一个有效示例:

App.js

import React, { useState } from "react"
import { useForm } from "react-hook-form"
import { useHistory } from "react-router-dom";
import { yupResolver } from '@hookform/resolvers'
import * as yup from "yup"
import axios from 'axios'

const schema = yup.object().shape({
  username: yup.string().required("Please enter Username."),
  password: yup.string().required("Please enter Password.")
})

export default function Login() {

  const [loginFailed, setLoginFailed] = useState(false);

  const { register, handleSubmit, errors } = useForm({
    resolver: yupResolver(schema)
  })

  const history = useHistory();

  const onSubmit = data => {
    axios.post('http://0.0.0.0:5000/login', data)
      .then((response) => {
        if (response.data.success) {
          history.push("/")
        } else {
          setLoginFailed(true)
        }
      })
      .catch(console.log)
  }

  return (
     
    <form className="login-form" onSubmit={handleSubmit(onSubmit)}>
      
      {loginFailed && <p>Invalid Username/Password.</p>}

      <input type="text" name="username" placeholder="Mobile Number" ref={register} />
      <p className="error">{errors.mobile?.message}</p>
        
      <input type="password" name="password" placeholder="Password" ref={register} />
      <p className="error">{errors.password?.message}</p>
      
      <input type="submit" value="Login" />
    </form>
  )
}

server.js

const cors = require('cors')
var express = require('express')
var router = express.Router()


router.post('/login', function(req, res, next) {
  return res.json({ success: false })
})

var app = express()
app.use(cors())
app.options('*', cors())
app.use('/', router)

app.listen(5000, () => {
  console.log(`Example app listening at http://localhost:${5000}`)
})

请注意,我在 axios.post 中添加了 catch 来处理错误,并且没有重新创建 passport 内容,只是返回 {success: false 来测试代码。 此外,正如评论中提到的那样,最好使用 false 而不是 null 来初始化布尔状态。

kaveh
2020-08-04

问题在于使用表单标签。

您需要修改表单提交操作为

const handleFormSubmit = (e) => {
   e.preventDefault();
   handleSubmit(onSubmit);
}
<form className="login-form" onSubmit={(e) => handleFormSubmit(e)}>
...
...
</form>

默认情况下,表单提交操作会触发重新加载操作,这会导致您出现问题。

groot
2020-08-07