react 输入框结合下拉框选择失焦问题
问题:每次输入名字后,点击空白处,发现并没有请求,但是点击控制台区域,就正常请求了。
<Select
style={{ width: 120, marginRight: 10 }}
placeholder="选择姓名"
value={item.userName}
showSearch
allowClear
filterOption={(input, option) =>
(option?.children as string).toLowerCase().indexOf(input.toLowerCase()) >= 0
}
onSearch={(val) => {
console.log('搜索关键词:', val); // 打印搜索关键词
setSearchValue(val)}} // 禁止动态添加选项
searchValue={searchValue}
onChange={(value) =>{
onSelectName(value, item, i);
setSearchValue('');
}}
onBlur={(e) => Information(e, item, i)}
onKeyDown={(e) => {
if (e.keyCode === 13) {
Information(e, item, i);
}
}}
>
{personNameOptions.map(option => (
<Option key={option.value} value={option.value}>{option.label}</Option>
))}
</Select>
解决:使用Dropdown组件+input组件
<Dropdown
overlay={
<Menu>
{personNameOptions.map(option => (
<Menu.Item
key={option.value}
onClick={() => {
onSelectName(option.value, item, i);
}}
>
{option.label}
</Menu.Item>
))}
</Menu>
}
visible={visible}
onVisibleChange={(v) => setVisible(v)}
>
<Input
value={item.inputValue || ''}
onChange={(e) => handleInputChange(e, i)}
onBlur={() => handleInputConfirm(i)}
onPressEnter={() => handleInputConfirm(i)}
/>
</Dropdown>
总结
1. 状态管理方式不同
原始代码
使用全局的 searchValue 状态管理所有输入框的搜索值
输入框值通过 Select 组件的 searchValue 和 onSearch 控制
问题:所有输入框共享同一个状态,导致交互冲突
修改后代码
为每个信息项(InformationItem)添加独立的 inputValue 属性
每个输入框维护自己的状态,互不干扰
优势:避免状态共享导致的值覆盖问题
// 修改后的数据结构
interface InformationItem {
// ...
inputValue?: string; // 新增字段
}
2. 输入处理逻辑不同
原始代码
使用 Information 函数处理 blur 和 enter 事件
依赖全局 searchValue,容易丢失上下文
问题:点击空白处时可能无法正确获取当前输入值
修改后代码
使用独立的 handleInputChange 和 handleInputConfirm 函数
直接通过数组索引操作对应项的状态
优势:确保总能获取正确的输入值
typescript
// 修改后的处理函数
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>, i: number) => {
const newInforMation = [...inforMation];
newInforMation[i].inputValue = e.target.value;
setInforMation(newInforMation);
};
const handleInputConfirm = (i: number) => {
const value = inforMation[i]?.inputValue?.trim();
if (value) onSelectName(value, inforMation[i], i);
};
3. 组件类型不同
原始代码
使用 Select 组件实现搜索选择
需要处理 onSearch、onChange、onBlur 等多个事件
修改后代码
改用 Input + Dropdown 组合
更直接地控制输入行为
优势:避免 Select 组件的一些默认行为干扰
jsx
{/* 修改后的输入组件 */}
<Dropdown
overlay={/* 下拉菜单 */}
>
<Input
value={item.inputValue || ''}
onChange={(e) => handleInputChange(e, i)}
onBlur={() => handleInputConfirm(i)}
onPressEnter={() => handleInputConfirm(i)}
/>
</Dropdown>
4. 数据持久化策略不同
原始代码
在 onBlur 和 onChange 中都会清空 searchValue
导致输入后值立即消失
修改后代码
不再自动清空输入值
仅在API成功返回后更新数据
优势:保留用户输入,体验更友好
typescript
// 修改后的API处理
getUserInfoByName(name: string, item: InformationItem, i: number) {
api.getUserInfoByPersonNameApi({ personName: name })
.then(res => {
// 成功时更新数据但保留inputValue
newInforMation[i] = {
...newInforMation[i],
inputValue: name // 关键区别:保留输入值
};
})
.catch(err => {
// 错误时也保留输入值
});
}
5. 类型安全性增强
修改后代码新增
明确定义 InformationItem 接口
所有状态操作都遵循TypeScript类型检查
优势:减少运行时错误
typescript
interface InformationItem {
userId: string;
userName: string;
email: string;
edit: boolean;
belongResId?: string;
inputValue?: string; // 新增
isAdd?: boolean; // 新增
}
- 不可变数据实践
修改后代码改进
所有状态更新都先创建新数组
避免直接修改原状态
优势:符合React最佳实践
typescript
// 示例:添加新项
const addInformat = (i: number) => {
const newInforMation = [...inforMation]; // 先复制
newInforMation.splice(i + 1, 0, {
/* 新对象 */
});
setInforMation(newInforMation); // 再更新
};
总结对比表