React动态添加发票项时ItemCost显示异常问题求助
问题根源
你现在的问题核心是把单个商品项的状态和多商品项数组分开管理了:
- 单独声明的
ItemName/ItemPrice/ItemQuantity/ItemCost是全局状态,所有商品项共享同一个值,修改任意一个项的输入,所有项都会同步变化;添加新项时,之前项的计算值会被新的全局状态覆盖,导致异常显示。 - 渲染时input的
value绑定的是inputField.ItemName,但你inputFields数组里的键是item_name(下划线小写),大小写不匹配,导致输入值无法正确绑定到数组对象中。 ItemCost是计算值,不需要单独状态,更不需要给不可编辑的p标签加onChange事件。
修复方案
把所有商品项的状态统一放到inputFields数组里,每个项单独管理自己的字段,修改时针对对应索引的项更新,同时实时计算该项的总价。
重构后的完整代码
状态与事件处理部分
import { useState } from 'react'; const InvoiceForm = () => { // 只保留多商品项数组状态,去掉单独的Item系列状态 const [inputFields, setInputFields] = useState([ { item_name: '', item_price: '', item_quantity: '', item_cost: '' }, ]); const handleSubmit = (e) => { e.preventDefault(); console.log("InputFields", inputFields); }; const handleAdd = () => { setInputFields([...inputFields, { item_name: '', item_price: '', item_quantity: '', item_cost: '' }]); }; const handleRemove = (index) => { const values = [...inputFields]; values.splice(index, 1); setInputFields(values); }; // 统一处理每个项的输入变化,同时计算总价 const handleInputChange = (index, e) => { const { name, value } = e.target; const updatedFields = [...inputFields]; // 更新当前项的对应字段 updatedFields[index][name] = value; // 实时计算当前项的总价(只有单价和数量都有值时计算) if (name === 'item_price' || name === 'item_quantity') { const price = parseFloat(updatedFields[index].item_price) || 0; const quantity = parseInt(updatedFields[index].item_quantity) || 0; updatedFields[index].item_cost = (price * quantity).toFixed(2); } setInputFields(updatedFields); }; return ( <form onSubmit={handleSubmit}> {/* 渲染部分见下方 */} </form> ); }; export default InvoiceForm;
输入字段渲染部分
{inputFields.map((inputField, index) => ( <div key={index} className="item_container"> <div className='item_fields'> <input name="item_name" value={inputField.item_name} onChange={(e) => handleInputChange(index, e)} type="text" placeholder="Item Name" /> <input name="item_price" value={inputField.item_price} onChange={(e) => handleInputChange(index, e)} type="number" step="0.01" // 支持小数单价 placeholder="Item Price" /> <input name="item_quantity" value={inputField.item_quantity} onChange={(e) => handleInputChange(index, e)} type="number" min="1" // 数量至少为1 placeholder="Quantity" /> {/* 不可编辑的总价展示,直接取当前项的item_cost */} <p className="item_cost"> {inputField.item_cost || '0.00'} </p> </div> <div className="buttons"> <button disabled={inputFields.length === 1} onClick={() => handleRemove(index)} className='remove_btn'>Remove</button> {/* 把Add按钮只放在最后一个项,避免重复显示 */} {index === inputFields.length - 1 && <button type="button" onClick={handleAdd}>Add an item</button>} </div> </div> ))}
关键修改点说明
- 合并状态管理:去掉所有单独的
ItemXXX状态,所有商品项数据都存在inputFields数组中,每个项独立维护自己的字段。 - 统一输入处理:新增
handleInputChange方法,接收当前项的索引和事件对象,精准更新对应项的字段,同时实时计算该项的总价。 - 修正字段绑定:input的
value绑定改为和数组对象一致的item_name/item_price等下划线命名,确保值能正确同步。 - 移除无效事件:不可编辑的p标签去掉
value和onChange属性,直接渲染当前项的item_cost值。 - 优化细节:给价格输入加
step="0.01"支持小数,数量输入加min="1"限制最小值,Add按钮只在最后一个项显示(可选,避免重复)。
内容的提问来源于stack exchange,提问作者Othniel
相关产品推荐
相关产品推荐

