You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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"
/>

问题根源与解决方法

问题原因

  1. 错误使用defaultValue:defaultValue仅用于设置输入框的初始值,属于一次性赋值,后续Formik字段值更新不会触发输入框重新渲染。
  2. props顺序错误:{...props}放在自定义onChange、onBlur之后,会导致props中的同名事件覆盖自定义逻辑(若存在),同时也会影响值的绑定优先级。

修复步骤

  1. 将defaultValue={field.value}替换为value={field.value}:通过受控组件的方式绑定字段值,Formik上下文更新时输入框会自动同步显示新值。
  2. 调整{...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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 17:45:49