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

重写Formik Field的onChange后选项显示与表单更新异常排查

Formik动态验证+Field组件onChange失效解决方案

问题核心出在重写onChange时没有同步Formik的表单状态,导致选中的代币值无法更新到Formik的values中,自然不会显示。下面直接给可行的解决思路和代码示例:

1. 正确处理Field的onChange事件

自定义onChange逻辑时,必须先调用Formik提供的field.onChange同步表单值,再执行你的动态验证逻辑,不能直接覆盖原有onChange。

修正后的代码示例

import { Formik, Field, Form } from 'formik';

// 预设不同代币对应的最低支付值
const tokenMinAmounts = {
  ETH: 0.01,
  USDT: 10,
  BTC: 0.0001
};

const PaymentForm = () => {
  return (
    <Formik
      initialValues={{ tokenSymbol: '', paymentAmount: '' }}
      // 全局动态验证规则
      validate={(values) => {
        const errors = {};
        if (!values.tokenSymbol) {
          errors.tokenSymbol = '请选择支付代币';
        }
        // 根据选中的代币动态判断最低支付值
        if (values.paymentAmount) {
          const minAmount = tokenMinAmounts[values.tokenSymbol];
          if (minAmount && Number(values.paymentAmount) < minAmount) {
            errors.paymentAmount = `最低支付金额为 ${minAmount}`;
          }
        }
        return errors;
      }}
      onSubmit={(values) => {
        console.log('提交数据:', values);
      }}
    >
      {({ form }) => (
        <Form>
          {/* 支付代币选择框 */}
          <div>
            <label>选择支付代币</label>
            <Field name="tokenSymbol">
              {({ field }) => (
                <select
                  {...field}
                  onChange={(e) => {
                    // 第一步:先调用Formik原生onChange同步表单值
                    field.onChange(e);
                    // 第二步:执行动态验证逻辑(可选:自动清空或设置默认支付金额)
                    const selectedToken = e.target.value;
                    const minAmount = tokenMinAmounts[selectedToken];
                    // 可以自动把最低值填充到支付金额输入框
                    form.setFieldValue('paymentAmount', minAmount || '');
                    // 手动触发支付金额字段的验证
                    form.validateField('paymentAmount');
                  }}
                >
                  <option value="">请选择</option>
                  <option value="ETH">ETH</option>
                  <option value="USDT">USDT</option>
                  <option value="BTC">BTC</option>
                </select>
              )}
            </Field>
          </div>

          {/* 支付金额输入框 */}
          <div>
            <label>支付金额</label>
            <Field name="paymentAmount" type="number" />
            {/* 显示错误信息 */}
            {form.errors.paymentAmount && form.touched.paymentAmount && (
              <span style={{ color: 'red' }}>{form.errors.paymentAmount}</span>
            )}
          </div>

          <button type="submit">提交</button>
        </Form>
      )}
    </Formik>
  );
};

export default PaymentForm;

2. 关键注意事项

  • 不要单独用自己的state存储选中的代币,直接从Formik的values.tokenSymbol获取即可,避免状态不同步
  • 动态验证优先用Formik的全局validate函数,它能自动依赖所有表单字段的值,无需额外维护监听逻辑
  • 如果需要在onChange里做额外操作(比如填充默认值),调用form.setFieldValue或form.validateField即可,不要手动修改state

内容的提问来源于stack exchange,提问作者quent043

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 04:22:16