React函数组件中firstName字段表单校验不生效问题排查
你代码中存在4个核心问题导致校验不生效:
- 错误的空值判断逻辑:
state.data.firstName === 'undefined'是和字符串'undefined'做比较,就算firstName真的为undefined也无法命中。而且用户清空输入框时,拿到的是空字符串而非undefined,正确判断需要覆盖undefined、空字符串、全空格场景,应该写为!state.data.firstName?.trim()
- 错误的空值判断逻辑:
- useState更新逻辑错误:React函数组件的useState更新对象时是全量替换,不是类组件的浅合并。你在
handleTextareaChange里调用setState({data})会直接把state里的firstNameValid等校验字段清空;在valid函数里调用setState({ firstNameValid: 'xxx' })会把data字段直接清空,更新时必须用拓展运算符保留原有字段
- useState更新逻辑错误:React函数组件的useState更新对象时是全量替换,不是类组件的浅合并。你在
- 直接修改原state对象:
handleTextareaChange里直接修改从state中取出的data对象,属于直接突变原state,不符合React不可变数据原则,可能导致视图不触发更新
- 直接修改原state对象:
- 校验逻辑不完整:当前只做了firstName的校验,没有加校验不通过时阻止后续提交逻辑的判断
修正后的完整代码:
const [state, setState] = React.useState({ data: { firstName: 'milan', lastName: 'sai', number: '999', }, firstNameValid: '', lastNameValid: '', numberValid: '', }); const handleTextareaChange = (event) => { // 浅拷贝原data对象,不直接修改原state const newData = {...state.data}; newData[event.target.name] = event.target.value; // 拓展运算符保留原有state的其他字段 setState({ ...state, data: newData, }); }; const valid = () => { // 先清空上一次的校验提示 let firstNameValid = ''; if (!state.data.firstName?.trim()) { firstNameValid = 'Required.Please enter your given name.'; } // 保留原有字段再更新校验结果 setState({ ...state, firstNameValid }); // 校验不通过直接返回,阻止后续提交逻辑 if (firstNameValid) return false; // 校验通过后的提交逻辑写在下方 }; return ( <div> <VerticalSpacing size={ABLE_SPACING_SIZE.spacing4x} /> <h1 tabIndex="-1" className="HeadingB mt-sheet-heading"> {CMS.heading1} </h1> <VerticalSpacing size={ABLE_SPACING_SIZE.spacing3x} /> <TextField id="givenName" name="firstName" label={CMS.name} onChange={handleTextareaChange} value={state.data.firstName} /> <p>{state.firstNameValid}</p> <VerticalSpacing size={ABLE_SPACING_SIZE.spacing3x} /> <TextField id="familyName" name="lastName" label={CMS.familyName} onChange={handleTextareaChange} value={state.data.lastName} /> <p>{state.lastNameValid}</p> <VerticalSpacing size={ABLE_SPACING_SIZE.spacing3x} /> <TextField id="mobileNumber" name="number" label={CMS.mobile} onChange={handleTextareaChange} value={state.data.number} /> <p>{state.numberValid}</p> <VerticalSpacing size={ABLE_SPACING_SIZE.spacing4x} /> <ActionButton className={styles.saveCta} variant="HighEmphasis" label={CMS.saveCTA} onClick={() => valid()} /> </div> );
内容的提问来源于stack exchange,提问作者Milan Sai
相关产品推荐
相关产品推荐

