Formik调用setFieldValue后自定义TextField UI不更新的解决方法
Formik自定义TextField调用setFieldValue后UI不实时更新的解决方法
问题描述
我基于Formik实现表单,其中包含一个自定义TextField组件,该组件读取Formik上下文并根据字段值渲染内容。调用setFieldValue()后,Formik上下文内的字段值已更新,但TextField的UI并未同步刷新;只有切换到表单下一步再返回时,新值才会显示。推测是调用setFieldValue()时TextField组件未触发重新渲染,请问如何让文本框实时更新显示新值?
自定义TextField代码
import { FieldHookConfig, useField } from 'formik' import React from 'react' const TextField = ({ label, ...props }) => { const [field, meta, helper] = useField(props) return ( <div className="relative mb-2 flex w-full flex-col px-1 text-gray-800"> <input onChange={(e) => helper.setValue(e.target.value.trim())} onBlur={field.onBlur} {...props} id={props.name} placeholder={label.split('-')[0]} defaultValue={field.value} /> <label className="absolute -top-2.5 left-3 mt-1 inline-block bg-white text-xs text-gray-400" htmlFor={field.name} > {label} </label> {meta.error && meta.touched && ( <p className="px-2 text-sm text-red-500">{meta.error}</p> )} </div> ) }
点击事件函数代码
function handleAdaSelect(e) { console.log(e) formik.setFieldValue('name', e.value) }
TextField调用示例
<TextField label="Name" name="name" type="text" disabled className="border-0 focus:outline-none" />
问题根源与解决方法
问题原因
- 错误使用
defaultValue:defaultValue仅用于设置输入框的初始值,属于一次性赋值,后续Formik字段值更新不会触发输入框重新渲染。 - props顺序错误:
{...props}放在自定义onChange、onBlur之后,会导致props中的同名事件覆盖自定义逻辑(若存在),同时也会影响值的绑定优先级。
修复步骤
- 将
defaultValue={field.value}替换为value={field.value}:通过受控组件的方式绑定字段值,Formik上下文更新时输入框会自动同步显示新值。 - 调整
{...props}的位置:将其放在自定义onChange、onBlur之前,避免props中的事件或属性覆盖自定义逻辑。
修改后的TextField代码
import { FieldHookConfig, useField } from 'formik' import React from 'react' const TextField = ({ label, ...props }) => { const [field, meta, helper] = useField(props) return ( <div className="relative mb-2 flex w-full flex-col px-1 text-gray-800"> <input {...props} id={props.name} placeholder={label.split('-')[0]} value={field.value} onChange={(e) => helper.setValue(e.target.value.trim())} onBlur={field.onBlur} /> <label className="absolute -top-2.5 left-3 mt-1 inline-block bg-white text-xs text-gray-400" htmlFor={field.name} > {label} </label> {meta.error && meta.touched && ( <p className="px-2 text-sm text-red-500">{meta.error}</p> )} </div> ) }
内容的提问来源于stack exchange,提问作者Law
相关产品推荐
相关产品推荐

