在NextJS中结合Zustand处理Laravel登录验证错误
解决方案:在NextJS登录表单中展示Laravel返回的字段级验证错误
1. 扩展User Store存储字段级错误
首先修改useUserService.js,在状态中新增fieldErrors来保存后端返回的字段错误:
const initialState = { users: undefined, user: undefined, currentUser: undefined, fieldErrors: {} // 新增:专门存储字段级验证错误 } const userStore = create(() => initialState)
2. 修改Login方法解析并存储错误
在login函数的异常捕获逻辑中,解析Laravel返回的errors字段,存入store的同时保留全局错误提示:
login: async (email, password) => { alertService.clear() // 清除上一次的字段错误 userStore.setState({ fieldErrors: {} }) try { const currentUser = await fetch.post('/api/authentication/token', {email, password}) userStore.setState({ ...initialState, currentUser }) const returnUrl = searchParams.get('returnUrl') || '/dashboard' router.push(returnUrl) } catch (error) { // 解析后端返回的字段错误 const fieldErrors = error.response?.data?.errors || {} userStore.setState({ fieldErrors }) // 显示全局错误消息 const errorMessage = error.response?.data?.message || '登录失败' alertService.error(errorMessage) } },
3. 在Login组件中展示对应字段错误
修改Login组件,从useUserService获取fieldErrors,并在对应输入框下方渲染错误文本,同时给错误状态的输入框添加红色边框提示:
export default Login function Login() { const userService = useUserService() const { fieldErrors } = userService const { register, handleSubmit, formState } = useForm() async function onSubmit({ email, password }) { await userService.login(email, password) } return ( <> <form onSubmit={handleSubmit(onSubmit)} className="mt-10 grid grid-cols-1 gap-y-8"> <div> <label htmlFor="email" className="mb-3 block text-sm font-medium text-gray-700" > Email address </label> <input type="email" { ...register("email") } className={`block w-full appearance-none rounded-md border ${fieldErrors.email ? 'border-red-500' : 'border-gray-200'} bg-gray-50 px-3 py-2 text-gray-900 placeholder-gray-400 focus:border-blue-500 focus:bg-white focus:outline-none focus:ring-blue-500 sm:text-sm`} /> {/* 渲染email字段错误 */} {fieldErrors.email && ( <div className="mt-1 text-sm text-red-600"> {fieldErrors.email.join(', ')} </div> )} </div> <div> <label htmlFor="password" className="mb-3 block text-sm font-medium text-gray-700" > Password </label> <input { ...register("password") } type="password" className={`block w-full appearance-none rounded-md border ${fieldErrors.password ? 'border-red-500' : 'border-gray-200'} bg-gray-50 px-3 py-2 text-gray-900 placeholder-gray-400 focus:border-blue-500 focus:bg-white focus:outline-none focus:ring-blue-500 sm:text-sm`} /> {/* 渲染password字段错误 */} {fieldErrors.password && ( <div className="mt-1 text-sm text-red-600"> {fieldErrors.password.join(', ')} </div> )} </div> <div> <button disabled={formState.isSubmitting} className={"w-full group inline-flex items-center justify-center rounded-md py-2 px-4 text-sm font-semibold focus:outline-none focus-visible:outline-2 focus-visible:outline-offset-2 bg-blue-600 text-white hover:text-slate-100 hover:bg-blue-500 active:bg-blue-800 active:text-blue-100 focus-visible:outline-blue-600 " + (formState.isSubmitting ? ButtonSpinner['btn-loading'] : "")} > <span>Sign in <span aria-hidden="true">→</span></span> </button> </div> </form> </> ) }
说明
- Laravel返回的错误是数组格式(比如
email: ["The email field is required."]),所以用join(', ')把多个错误拼接成字符串 - 每次提交前清除字段错误,避免旧错误干扰新的提交
- 通过动态添加
border-red-500类,让用户直观看到哪个输入框有问题
内容的提问来源于stack exchange,提问作者BigJobbies
相关产品推荐
相关产品推荐

