如何使用use hook form计算总价并实时同步至禁用输入框?
解决实时更新总价输入框的问题
要实现会员类型或单价变化时实时更新总价,核心是监听这两个字段的变化,实时计算并更新表单的total字段,同时让组件重新渲染显示最新值。
关键修改点:
- 从
useForm中解构出setValue方法,用于更新表单字段 - 使用
useEffect监听membershipType和price的变化,实时计算总价并更新total - 处理输入框的字符串转数字问题,避免计算出错
- 正确渲染禁用的总价输入框
修改后的完整代码:
import { useEffect } from 'react'; import { useForm } from 'react-hook-form'; import { yupResolver } from '@hookform/resolvers/yup'; import ValidationSchema from './your-validation-schema-path'; // 替换为你的验证文件路径 type Member = { assignedBy: string name: string lastName: string gender: string phone: number membershipType: string startingDate: string price: number total: number } const AddMember = () => { const form = useForm<Member>({ defaultValues: { assignedBy: 'admin', name: '', lastName: '', gender: '', membershipType: '', startingDate: '', total: 0, price: 0 // 给price设置默认数字值,避免初始为undefined }, resolver: yupResolver(ValidationSchema) }); const { register, control, handleSubmit, formState, watch, setValue } = form; const { isDirty, errors } = formState; const watchMembershipType = watch('membershipType'); const watchPrice = watch('price'); // 实时计算总价的逻辑 useEffect(() => { // 处理price为字符串的情况,转成数字,默认0 const numericPrice = typeof watchPrice === 'string' ? parseFloat(watchPrice) || 0 : watchPrice || 0; let calculatedTotal = 0; switch (watchMembershipType) { case '1 month': calculatedTotal = numericPrice; break; case '3 months': calculatedTotal = numericPrice * 3 * 0.9; // 简化计算:10%折扣即乘以0.9 break; case '1 year': calculatedTotal = numericPrice * 12 * 0.8; // 20%折扣即乘以0.8 break; default: calculatedTotal = 0; } // 更新表单的total字段 setValue('total', calculatedTotal, { shouldValidate: false }); // 不需要验证total字段 }, [watchMembershipType, watchPrice, setValue]); // 依赖变化时触发 const onSubmit = (data: Member) => { // 提交时total已经是最新值,无需再计算,直接使用即可 console.log(data); } return ( <div className='add-member'> {/* 其他表单代码 */} <div className='input' id='price-input'> <label>Price </label> <input {...register('price', { valueAsNumber: true })} // 使用valueAsNumber自动转数字 placeholder='$ (per month)' className={errors.price?.message ? 'error' : ''} /> </div> <div className='input' id='price-total'> <label>Total</label> <input {...register('total')} disabled className={errors.total?.message ? 'error' : ''} /> </div> <button type='submit' disabled={!isDirty}>Submit</button> <DevTool control={control} /> </div> ) } export default AddMember
代码说明:
setValue的使用:通过setValue更新表单的total字段,这样表单内部状态会同步,输入框会自动显示最新值。useEffect监听变化:当membershipType或price改变时,自动触发计算并更新总价。valueAsNumber处理输入:给price的register添加valueAsNumber,自动将输入的字符串转为数字,避免后续计算出现NaN。- 简化折扣计算:把
(price*3)-(price*3*0.1)简化为price*3*0.9,逻辑更清晰。 - 默认值处理:给
price设置默认值0,避免初始状态下watchPrice为undefined导致计算错误。
这样修改后,当用户选择会员类型或修改单价时,总价输入框会实时更新显示计算结果,提交时data.total也会是最新的正确值。
内容的提问来源于stack exchange,提问作者user23367986
相关产品推荐
相关产品推荐

