React问题:Input组件的defaultValue为何无法更新?
问题分析与解决方案
你的问题核心在于**defaultValue 只在组件首次挂载时生效,后续 props 变化不会触发它更新**——这是 React 非受控组件的特性,defaultValue 只是初始值,而非动态绑定的数据源。当 zipData 更新后,Input 组件并不会自动读取新的 defaultValue,所以才会出现数据不同步的情况。
结合你使用的表单库(从 useField、registerField 和 addressFormRef.current?.setErrors 来看,应该是类似 React Hook Form 这类表单管理库),正确的做法是让表单库统一管理字段值,而非依赖 defaultValue。下面是具体的修复步骤:
1. 获取 CEP 数据后,主动更新表单字段值
在 handleZipCode 函数中,成功获取 zip 数据时,除了更新 zipData,还要调用表单实例的 setValue 方法更新对应字段的值。这样表单库会维护字段状态,自动同步到绑定的 Input 组件:
const handleZipCode = useCallback( async ({ target }: ChangeEvent<HTMLInputElement>) => { const { value } = target; try { if (value.length === 9 && isDigit(value[8])) { const zip = await cep(value); if (zip?.city) { setZipData(zip); // 新增:调用表单的 setValue 方法更新地址字段 addressFormRef.current?.setValue('user_address', zip.street); // 如有其他关联字段(如城市、州),可一并更新 addressFormRef.current?.setValue('user_city', zip.city); addressFormRef.current?.setValue('user_state', zip.state); } else { addressFormRef.current?.setErrors({ user_zip_code: 'CEP not found' }); } } } catch (e) { addressFormRef.current?.setErrors({ user_zip_code: e.message ?? 'CEP not found' }); } }, [isDigit] );
2. 移除 Input 组件的 defaultValue,交由表单库管理状态
表单库会自动维护字段值并同步到组件,因此不需要再手动传递 defaultValue:
<fieldset> <legend>Address</legend> <Input mask='' name='user_address' placeholder='Rua um dois três' {/* 移除 defaultValue,由表单库管理值的同步 */} /> </fieldset>
3. (可选)优化自定义 Input 组件的受控同步
如果你的 useField 钩子返回字段当前的 value,可以将 Input 改为受控模式,直接绑定 value 属性并监听变化:
const Input: React.FC<InputProps> = ({ name, ...rest }) => { const { fieldName, value, registerField, error } = useField(name); const inputRef = useRef(null); useEffect(() => { registerField({ name: fieldName, ref: inputRef.current, path: 'value', setValue(ref: any, value: string) { ref.setInputValue(value); }, clearValue(ref: any) { ref.setInputValue(''); }, }); }, [fieldName, registerField]); // 监听表单字段值变化,同步到输入框 useEffect(() => { if (inputRef.current && value !== undefined) { inputRef.current.setInputValue(value); } }, [value]); return ( <Container> <ReactInputMask ref={inputRef} value={value} {/* 绑定受控值 */} {...rest} /> {error && <Error>{error}</Error>} </Container> ); };
这样当表单字段值更新时,Input 会自动同步最新内容,确保数据一致性。
总结来说,你之前的错误是依赖非受控组件的 defaultValue 实现动态更新,正确的思路是利用表单库的状态管理能力,主动更新字段值并让组件与表单状态绑定。
内容的提问来源于stack exchange,提问作者augusto amaral
相关产品推荐
相关产品推荐

