React JS添加onChange后输入框输入失焦、回退默认值问题排查
问题根因
- 子组件定义放在父组件内部导致反复卸载重挂载
你把ConditionalTableRow、TableRowWithSave两个组件的定义写在了AddMaker组件内部,每次AddMaker因为状态更新重渲染时,这两个组件都会生成全新的函数实例,React会判定为不同的组件类型,直接销毁旧组件实例再创建新的,所以输入框会失焦,且回到初始的defaultValue。 - Input属性不匹配,未做受控绑定
你给input加了onChange修改make状态,但没有把input的value绑定到make,仅用了只在首次渲染生效的defaultValue,状态修改后不会同步到输入框显示,属于半受控的异常状态。 - 编辑状态共用不合理(多行编辑场景下)
当前全局只有一个make状态,如果有多行同时进入编辑模式,所有行的输入会共用同一个状态,逻辑存在问题。 - 列表key使用index存在隐患
当列表增删、排序时,用index作为key会导致组件复用异常,加重失焦问题。
修复方案
- 把
ConditionalTableRow、TableRowWithSave两个组件移到AddMaker组件外部,避免每次父组件渲染都生成新的组件类型。 - 将input改为完全受控组件,绑定
value属性到对应状态;如果需要支持多行编辑,建议给每条记录加单独的编辑状态,或者用对象存储不同行的输入值。 - 列表的key替换为每条记录的唯一标识字段(比如id),不要用index。
修正后参考代码
// 子组件移到父组件外部定义 function TableRowWithSave({ item, onInputChange, onSave }) { return ( <TableRow> <TableCell> {/* 改为受控组件,绑定value和onChange */} <input type="text" value={item.editMake ?? item.make} onChange={e => onInputChange(item.id, e.target.value)} /> </TableCell> <TableCell> <button className="palletSaveButton" onClick={() => onSave(item.id)}> Save </button> </TableCell> </TableRow> ) } function TableRowWithEdit({ item, index, onEnterEdit }) { // 原有TableRowWithEdit的逻辑,补充你自己的实现即可 return <TableRow onClick={() => onEnterEdit(index)}> <TableCell>{item.make}</TableCell> <TableCell><button>编辑</button></TableCell> </TableRow> } function ConditionalTableRow(props) { const { item, index, editModeIndex, onInputChange, onSave, onEnterEdit } = props; if ( index === editModeIndex) return <TableRowWithSave item={item} index={index} onInputChange={onInputChange} onSave={onSave} /> else return <TableRowWithEdit item={item} index={index} onEnterEdit={onEnterEdit} /> } const AddMaker = () => { // 假设records、editModeIndex是你已经定义的原始数据和编辑行状态 const [records, setRecords] = useState(/* 你的原始数据 */); const [editModeIndex, setEditModeIndex] = useState(-1); const handleInputChange = (recordId, value) => { setRecords(prev => prev.map(item => { if(item.id === recordId) { // 临时存储编辑值 return {...item, editMake: value} } return item })) } const handleSaveClick = (recordId) => { setRecords(prev => prev.map(item => { if(item.id === recordId) { // 保存时把editMake覆盖到make,清除临时编辑值 return {...item, make: item.editMake, editMake: undefined} } return item })) setEditModeIndex(-1) } return ( <TableBody> { records.map((item, index) => ( // key用item的唯一id,不用index <ConditionalTableRow key={item.id} item={item} index={index} editModeIndex={editModeIndex} onInputChange={handleInputChange} onSave={handleSaveClick} onEnterEdit={setEditModeIndex} /> )) } </TableBody> ); }
内容的提问来源于stack exchange,提问作者nour
相关产品推荐
相关产品推荐

