react中 input中输入后自动失去焦点
问题
小组小伙伴开发过程中,遇到遍历 input 渲染在页面,再通过input框操作修改数据的过程中,出现input失去焦点问题。 去帮忙排查问题的时候,起初分析是 onChange 方法的问题,因为项目里业务逻辑比较复杂,方法的转换有很多层级,从上到下一步步排查都没能找到原因。偶然间看到外层遍历的key值用的时间戳,再想到react的机制,便知道原因了
代码示例如下:
import React, { useState } from 'react';
import { Input } from 'antd';
const App = () => {
const [userArr, setUserArr] = useState<{value:string}[]>([
{ val:'你好你好1' },
{ val:'你好你好2' },
{ val:'你好你好3' },
]);
const fns = (index:number, e:any)=>{
const userArrR = JSON.parse(JSON.stringify(userArr));
userArrR[index].val = e.target.value;
setUserArr(userArrR);
}
return (
<div>
{
userArr.map((item, index)=>{
return (
<div key={ index + new Date().getTime() }>
<Input value={ item.val } onChange={ fns.bind(this, index) } />
</div>
)
})
}
</div>
);
}
export default App
可以看到key值使用了时间戳
key={index + new Date().getTime() }
这个时候的key是会动态变化的,因为每次数据状态发生变化都会触发render 重写渲染,即视图重写渲染
解决办法:
将map遍历时绑定的key的值改为不是动态变化的值(例如index 每一项的索引值,或给每一项设置一个固定的key或id)
原因:
当然这个Demo只是用来展示输入后就立马失去焦点的原因,我们只需要保证每次的Key不变即可,同时在父组件强制渲染时我们可以使用memo
函数来保证子组件不变,在React,每一次输入都会触发onChange事件都会重新调用render(),这个key的作用就是避免diff算法重新生成一个全新的dom,所以每当绑定的key变化时diff算法就会生成一个全新的dom,进而导致每次输入都会导致input会失去焦点。
注意:
在React的key选用上尽量避免使用index(除非保证当前item对应的index不会变),在Api获取数组时通常会携带id属性,在数据表中经常作为主键,我们可以使用他来作为Key,如果没有携带id,我们可以使用:固定字符串+item.text+index的形式,例如:{`article-item-${item.title}+${index}`}