You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React JS添加onChange后输入框输入失焦、回退默认值问题排查

问题根因

  1. 子组件定义放在父组件内部导致反复卸载重挂载
    你把ConditionalTableRow、TableRowWithSave两个组件的定义写在了AddMaker组件内部,每次AddMaker因为状态更新重渲染时,这两个组件都会生成全新的函数实例,React会判定为不同的组件类型,直接销毁旧组件实例再创建新的,所以输入框会失焦,且回到初始的defaultValue。
  2. Input属性不匹配,未做受控绑定
    你给input加了onChange修改make状态,但没有把input的value绑定到make,仅用了只在首次渲染生效的defaultValue,状态修改后不会同步到输入框显示,属于半受控的异常状态。
  3. 编辑状态共用不合理(多行编辑场景下)
    当前全局只有一个make状态,如果有多行同时进入编辑模式,所有行的输入会共用同一个状态,逻辑存在问题。
  4. 列表key使用index存在隐患
    当列表增删、排序时,用index作为key会导致组件复用异常,加重失焦问题。

修复方案

  1. 把ConditionalTableRow、TableRowWithSave两个组件移到AddMaker组件外部,避免每次父组件渲染都生成新的组件类型。
  2. 将input改为完全受控组件,绑定value属性到对应状态;如果需要支持多行编辑,建议给每条记录加单独的编辑状态,或者用对象存储不同行的输入值。
  3. 列表的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 07:48:03