React对接Firebase登录首次报错返回undefined第二次才正常显示问题
问题根因
- React的状态更新是批量异步执行的,调用
displayError内部的setError后,当前执行上下文里的authCtx.errorMessage还是更新前的旧值,你紧接着调用setError(authCtx.errorMessage)取到的是未更新的旧状态,所以首次触发返回空/undefined,第二次触发才能取到上一次更新好的错误信息。 - Context中的状态类型不匹配:初始定义
useState({error:""})是对象类型,但后续setError直接传入字符串,首次渲染时如果直接读取errorMessage渲染会出现类型异常,直到第二次赋值为字符串后才正常显示。
修复方案
方案1(推荐):移除父组件冗余的状态存储
错误信息已经统一存在Context中,无需在父组件额外维护一份状态,直接在需要展示错误的子组件中消费Context的errorMessage即可。
修改父组件fetch方法的错误分支,删掉多余的本地setError调用:
if (!response.ok) { if (action === 'LOGIN') { authCtx.displayError(data.error.message, 'LOGIN'); } else { authCtx.displayError(data.error.message, 'SUBMIT'); } return; }
同时修正Context的初始状态,统一为字符串类型:
// 把初始对象改成空字符串 const [error, setError] = useState("");
子组件直接通过useContext拿到errorMessage渲染即可。
方案2:让displayError返回处理后的错误信息
如果需要在父组件单独存储错误信息,直接修改displayError方法返回处理好的错误字符串,不用从Context的未更新状态中取值:
const displayError = (errorMessage, action) => { let finalError = ''; if (action === 'LOGIN') { switch (errorMessage) { case 'INVALID_PASSWORD': finalError = 'Incorrect password, please try again!'; break; case 'EMAIL_NOT_FOUND': finalError = 'Email not found in system, please sign up.'; break; case 'INVALID_EMAIL': finalError = "Please don't leave the email field blank!"; break; case 'MISSING_PASSWORD': finalError = "Please don't leave password field blank!"; break; default: finalError = 'Too many failed attempts on this account, please wait a few minutes or reset your password to try again!'; } } else { switch (errorMessage) { case 'EMAIL_EXISTS': finalError = 'Email already exists, please try again or sign in.'; break; case 'MISSING_PASSWORD': finalError = "Please don't leave password field blank!"; break; case 'MISSING_EMAIL': finalError = "Please don't leave the email form blank!"; break; case 'WEAK_PASSWORD : Password should be at least 6 characters': finalError = 'Weak password, password should be at least 6 characters!'; break; default: finalError = 'Something went wrong, please try again!'; } } setError(finalError); return finalError; };
父组件调用时直接取返回值:
if (!response.ok) { let errMsg; if (action === 'LOGIN') { errMsg = authCtx.displayError(data.error.message, 'LOGIN'); } else { errMsg = authCtx.displayError(data.error.message, 'SUBMIT'); } setError(errMsg); return; }
内容的提问来源于stack exchange,提问作者Charles Pine
相关产品推荐
相关产品推荐

