ReactJS使用Yup做表单校验时数组长度始终为0问题求解
问题原因
formSchema.validate是异步方法,你的代码在同步位置读取数组长度时,校验的回调逻辑还未执行,数组还没有被推入元素,所以长度为0。控制台展示数组有元素是因为控制台对引用类型的打印是懒加载的,你点击展开数组时异步逻辑已经执行完成,和打印当时的数组状态不是同一个时间点的结果。- 你用普通变量
let name = []存储错误信息,不属于React的响应式状态,就算后续异步逻辑修改了这个数组,React也不会触发组件重新渲染,页面上的长度永远是初始渲染时的0。 - 校验逻辑直接写在组件根作用域,每次组件重新渲染都会触发一次校验,会产生不必要的性能消耗。
解决方法
将错误列表改为响应式状态,把校验逻辑放到副作用钩子中执行,修改后的代码如下:
import { useState, useEffect } from 'react' import * as yup from 'yup' const formSchema = yup.object().shape({ firstName: yup.string().required(), lastName: yup.string().required(), email: yup.string().email().required(), password: yup.string().min(8).required() }) export const App = () => { const [values, setValues] = useState({ firstName: '', lastName: '', email: '', password: '' }) // 用state存储错误列表,支持响应式更新 const [errors, setErrors] = useState([]) useEffect(() => { // 每次values变更时重新执行校验 formSchema.validate(values, { abortEarly: false }) .then(() => { // 校验通过清空错误 setErrors([]) }) .catch((err) => { const errorList = err.inner.map(error => ({ [error.path]: error.message })) setErrors(errorList) }) }, [values]) // 依赖values,只有values变化才重新校验 console.log(errors) console.log(errors.length) return ( <div> <h1>hello</h1> <h1>{errors.length}</h1> </div> ) }
修改点说明:
- 用
useState定义errors状态存储校验错误,修改后会自动触发组件重新渲染 - 把校验逻辑包裹在
useEffect中,只有表单值values变化时才重新执行校验,避免无效重复执行 - 校验完成后直接通过
setErrors更新状态,确保可以同步拿到最新的错误列表长度
内容的提问来源于stack exchange,提问作者en nice
相关产品推荐
相关产品推荐

