重写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
相关产品推荐
相关产品推荐

