React表单提交后错误消息无法即时显示问题求助
问题根源:Firebase登录是异步操作,你的同步写法导致状态更新滞后
兄弟,我一眼就看出问题所在了——你把异步操作当成同步来处理了!
先给你拆解清楚:
- 你之前的模拟
login函数是同步逻辑,调用后能立刻返回结果,所以response能马上拿到,紧接着更新state,错误消息自然能即时显示。 - 但Firebase的
signInWithEmailAndPassword是基于Promise的异步操作,你的login函数根本没等这个异步请求完成就结束了!这时候response其实是undefined,你执行if(!response)的时候,auth.error还没被catch里的代码赋值(因为catch要等登录请求失败后才会触发)。等你第二次点击登录时,上一次请求的错误才被设置到auth.error里,这时候更新state才会显示错误,所以才会出现“多次点击才显示”的情况。
解决方案:两种方式搞定异步逻辑
方式一:让login函数返回Promise,用async/await处理
先修改Functions.js里的login函数,让它返回Promise:
function login(data) { // 直接返回Firebase的Promise return Firebase.auth().signInWithEmailAndPassword(data.email, data.pass) .then(() => true) .catch((error) => { auth.error = error.message; return false; }); }
注意这里我把data.password改成了data.pass,因为你的组件state里存的是pass,之前的变量名不匹配会导致密码传错!
然后把组件的handleSubmit改成async函数,等待login的结果:
async handleSubmit(e) { e.preventDefault(); const response = await auth.login(this.state); if (!response) { this.setState({ error: auth.error }); } }
方式二:直接在组件里处理异步逻辑(更推荐)
其实没必要把错误存在外部的auth对象里,React组件的状态最好自己管理,这样更不容易出现状态不同步的问题:
handleSubmit(e) { e.preventDefault(); const { email, pass } = this.state; Firebase.auth().signInWithEmailAndPassword(email, pass) .then(() => { // 登录成功后的逻辑,比如跳转到首页 console.log("登录成功!"); }) .catch((error) => { // 直接把错误消息设置到组件state里 this.setState({ error: error.message }); }); }
这种写法更直观,也避免了外部状态和组件state不同步的坑。
最后再提个小细节
你的密码输入框类型是text,建议改成password,这样输入的密码会被隐藏,更符合登录表单的规范:
<input type="password" name="pass" onChange={this.handleChange}/>
内容的提问来源于stack exchange,提问作者meteliov
相关产品推荐
相关产品推荐

