React中如何在单个useEffect中处理多状态联动的表单校验逻辑
React表单校验多useEffect合并方案
错误原因
你合并后代码运行异常主要是两个问题导致的:
- 依赖项缺失:合并后的effect逻辑中用到了
errors和onHideError,但你没有将这两个变量加入依赖数组,导致effect运行时读取的是首次渲染的旧errors快照,判断逻辑无法生效。 - 数组真值判断有潜在风险:
friends和socials是数组类型,空数组[]在JS中属于真值,如果你要判断用户是否选择了内容,用friends.length > 0判断会更稳妥,避免空数组被误判为已填写。
修复方案
基础可用版
补全所有依赖,修正数组判断逻辑即可正常运行:
useEffect(() => { if (name && errors.includes('nameNotProvided')) { onHideError('nameNotProvided') } if (friends.length > 0 && errors.includes('friendsNotSelected')) { onHideError('friendsNotSelected') } if (socials.length > 0 && errors.includes('socialsNotSelected')) { onHideError('socialsNotSelected') } }, [ name, friends, socials, errors, onHideError ])
性能优化版(和原多useEffect行为完全一致)
如果你想和原来多个useEffect的行为完全一致,即只有对应字段变化时才处理该字段的错误、避免不必要的判断,可以用useRef存储上一次的字段值,只处理发生变化的字段:
const MyComponent = ({}) => { const [ name, setName ] = useState('') const [ friends, setFriends ] = useState([]) const [ socials, setSocials ] = useState([]) const [ errors, setErrors ] = useState([]) // 存储上一次的字段值 const prevFieldsRef = useRef({ name: '', friends: [], socials: [] }) // 用useCallback包裹onHideError避免effect频繁触发 const onHideError = useCallback((errorKey) => { setErrors(prev => prev.filter(item => item !== errorKey)) }, []) useEffect(() => { const prevFields = prevFieldsRef.current // 仅name变化时处理name相关错误 if (name !== prevFields.name) { if (name && errors.includes('nameNotProvided')) { onHideError('nameNotProvided') } } // 仅friends变化时处理friends相关错误 if (friends !== prevFields.friends) { if (friends.length > 0 && errors.includes('friendsNotSelected')) { onHideError('friendsNotSelected') } } // 仅socials变化时处理socials相关错误 if (socials !== prevFields.socials) { if (socials.length > 0 && errors.includes('socialsNotSelected')) { onHideError('socialsNotSelected') } } // 更新存储的上一次字段值 prevFieldsRef.current = { name, friends, socials } }, [ name, friends, socials, errors, onHideError ]) return (...) }
内容的提问来源于stack exchange,提问作者karo-s
相关产品推荐
相关产品推荐

