React输入框无法持续输入:点击后自动禁用问题求助
React输入框自动"失去焦点"问题解决方案
问题现象
开发React应用时遇到异常:每次点击输入框输入内容后,输入框会立刻失去焦点(表现类似被禁用);再次点击可重新输入,但输入后又会重复上述问题。
用户提供代码
TimeInputRow组件
const TimeInputRow = ({ data, onFieldChange, onAddRow }) => { console.log(data) const {existing_date, time_start, time_end, percent_to_count, days_addtion } = data; console.log(existing_date) // const formattedDate = new Date(existing_date).toLocaleDateString('en-GB'); return ( <div className='d-f time-adding'> {/* Use formattedDate instead of date */} <input type="text" value={existing_date || ""} onChange={(e) => onFieldChange('existing_date', e.target.value)} /> <input type="text" pattern="[0-2][0-9]:[0-5][0-9]:[0-5][0-9]" value={time_start} onChange={(e) => onFieldChange('time_start', e.target.value)} /> <input type="text" pattern="[0-2][0-9]:[0-5][0-9]:[0-5][0-9]" value={time_end} onChange={(e) => onFieldChange('time_end', e.target.value)} /> <input type="number" placeholder="Percent Count" value={percent_to_count} onChange={(e) => onFieldChange('percent_to_count', parseInt(e.target.value))} /> <input type="text" placeholder="Days Addtion" value={days_addtion} onChange={(e) => onFieldChange('days_addtion', e.target.value)} /> <button onClick={onAddRow} className='add-row'><FaRegPlusSquare /></button> </div> ); };
字段变更处理代码
const handleFieldChange = (index, field, value) => { const newRows = [...rows]; newRows[index][field] = value; setRows(newRows); }; {rows.map((data, index) => ( <div key={index} className='d-f'> <TimeInputRow key={index} data={data} onFieldChange={(field, value) => handleFieldChange(index, field, value)} onAddRow={handleAddRow} /> <button className='remove-row' onClick={() => handleRemoveRow(index)}><FaRegTrashAlt /></button> </div> ))} <button className='btn btn-primary' onClick={handleSubmit}>Save</button>
问题根源
- 用index作为React元素的key:数组更新时index会变动,React的diff算法会错误地复用/重建组件,导致输入框失去焦点,看起来像被禁用。
- 状态更新的不可变性不足:虽然复制了数组,但直接修改内部对象的属性,React可能无法正确识别状态变化,引发不必要的重渲染。
- 部分输入框value无兜底处理:比如
time_start如果初始值为undefined,会导致受控组件状态异常。
修复方案
1. 给每行数据加唯一ID,替换index作为key
初始化rows时给每个对象添加唯一标识:
// 初始化示例 const [rows, setRows] = useState([ { id: Date.now(), existing_date: "", time_start: "", time_end: "", percent_to_count: "", days_addtion: "" } ]);
渲染时用这个唯一ID作为key:
{rows.map((data, index) => ( <div key={data.id} className='d-f'> <TimeInputRow key={data.id} data={data} onFieldChange={(field, value) => handleFieldChange(index, field, value)} onAddRow={handleAddRow} /> <button className='remove-row' onClick={() => handleRemoveRow(index)}><FaRegTrashAlt /></button> </div> ))}
2. 优化状态更新逻辑,严格遵循不可变性
修改handleFieldChange,用函数式更新+对象扩展运算符返回全新对象:
const handleFieldChange = (index, field, value) => { setRows(prevRows => prevRows.map((row, i) => i === index ? { ...row, [field]: value } : row )); };
3. 给所有输入框的value添加兜底处理
避免value为undefined导致受控组件异常:
<input type="text" pattern="[0-2][0-9]:[0-5][0-9]:[0-5][0-9]" value={time_start || ""} onChange={(e) => onFieldChange('time_start', e.target.value)} /> <input type="text" pattern="[0-2][0-9]:[0-5][0-9]:[0-5][0-9]" value={time_end || ""} onChange={(e) => onFieldChange('time_end', e.target.value)} /> <input type="number" placeholder="Percent Count" value={percent_to_count || ""} onChange={(e) => onFieldChange('percent_to_count', parseInt(e.target.value) || 0)} /> <input type="text" placeholder="Days Addtion" value={days_addtion || ""} onChange={(e) => onFieldChange('days_addtion', e.target.value)} />
修复逻辑说明
- 唯一ID作为key能让React准确识别每个组件,避免数组变动时错误销毁/重建组件,保证输入框焦点稳定。
- 不可变状态更新能让React正确检测状态变化,只更新需要变动的组件,提升性能同时避免异常渲染。
- 兜底处理value确保受控组件状态始终有效,不会因undefined导致输入框行为异常。
内容的提问来源于stack exchange,提问作者Siva MCA
相关产品推荐
相关产品推荐

