React动态增减输入框遇event.target未定义问题及优化咨询
问题原因、修复与优化方案
一、handleFocusOut参数错误的原因
你在输入框的onBlur回调里调用handleFocusOut(index)时,只传递了index,没有传递事件对象event。这导致handleFocusOut函数的第一个参数event实际接收到的是index的值(比如0),自然不存在event.target属性,从而触发报错。
二、快速修复方法
修改输入框的onBlur回调,把事件对象传递进去:
<SpecificationValue placeholder="Key" onChange={handleSpecKeyChange} name="key" onBlur={(e) => handleFocusOut(e, index)} // 补充传递事件对象e /> <SpecificationValue placeholder="Value" onChange={handleSpecValueChange} name="value" onBlur={(e) => handleFocusOut(e, index)} // 同样修改此处 />
但这只是解决了当前报错,你的代码还存在核心问题:用单个specificationKeys和specificationValues状态存储所有输入框的值,新增输入框后,输入内容会覆盖之前的值,无法正确维护多组key-value的对应关系。
三、更优的实现方案
直接用specifications数组状态维护每一组输入项,每一项是包含key和value的对象,精准对应每一组输入框,同时简化逻辑:
修改后的App.js代码
import React, { useState } from "react"; import { SpecificationFormContainer, SpecificationFormCard, SpecificationFormTitle, SpecificationInputRow, SpecificationValue, AddMoreButton, RemoveButton } from "./Elements"; import "./styles.css"; export default function App() { // 用数组存储每一组规格,初始为空 const [specifications, setSpecifications] = useState([]); // 新增一组空的key-value项 const handleAdd = () => { setSpecifications(prev => [...prev, { key: "", value: "" }]); }; // 删除最后一组项 const handleRemove = () => { setSpecifications(prev => prev.slice(0, -1)); }; // 更新指定索引的key或value const handleInputChange = (index, field, value) => { setSpecifications(prev => { const newSpecs = [...prev]; newSpecs[index][field] = value; return newSpecs; }); }; // 提交时转换为需要的POST数据格式 const handleSubmit = (e) => { e.preventDefault(); const payload = specifications .filter(item => item.key.trim() && item.value.trim()) // 过滤空项 .map(item => ({ item: 1, ...item })); console.log("POST请求数据:", payload); // 此处可发起POST请求 }; return ( <SpecificationFormContainer> <SpecificationFormCard> <SpecificationFormTitle>Add Specifications</SpecificationFormTitle> <form onSubmit={handleSubmit}> {specifications.map((spec, index) => ( <SpecificationInputRow key={index}> <SpecificationValue placeholder="Key" value={spec.key} onChange={(e) => handleInputChange(index, "key", e.target.value)} /> <SpecificationValue placeholder="Value" value={spec.value} onChange={(e) => handleInputChange(index, "value", e.target.value)} /> </SpecificationInputRow> ))} <div> <AddMoreButton type="button" onClick={handleAdd}> Add </AddMoreButton> {specifications.length > 0 && ( <RemoveButton type="button" onClick={handleRemove}> Remove </RemoveButton> )} <button type="submit">提交</button> </div> </form> </SpecificationFormCard> </SpecificationFormContainer> ); }
方案优势
- 状态管理更合理:用数组存储每一组输入项,避免单个状态覆盖问题,key-value一一对应。
- 逻辑简化:无需额外维护
numberOfSpecFields,数组长度就是输入框组数,增删操作直接操作数组。 - 数据格式直接可用:提交时过滤空项,给每个对象添加
item:1即可得到目标POST结构。 - 受控组件实现:所有输入框为受控组件,状态与输入值保持同步,避免非受控组件的潜在问题。
四、扩展说明
- 若需支持删除任意一组,可给每个删除按钮绑定对应索引,修改
handleRemove为接收索引参数后删除对应项。 - 可在输入框
onBlur回调中添加空值校验,确保key和value不为空。
内容的提问来源于stack exchange,提问作者Ashutosh Chapagain
相关产品推荐
相关产品推荐

