问题
小组小伙伴开发过程中,遇到遍历 input 渲染在页面,再通过input框操作修改数据的过程中,出现input失去焦点问题。
去帮忙排查问题的时候,起初分析是 onChange 方法的问题,因为项目里业务逻辑比较复杂,方法的转换有很多层级,从上到下一步步排查都没能找到原因。偶然间看到外层遍历的key值用的时间戳,再想到react的机制,便知道原因了
代码示例如下:
import React, { useState } from 'react';
import { Input } from 'antd';
const index = () => {
const [userArr, setUserArr] = useState<any[]>([
{ 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 index
可以看到key值使用了时间戳
key={ index + new Date().getTime() }
这个时候的key是会动态变化的,因为每次数据状态发生变化都会触发render 重写渲染,即视图重写渲染
解决办法:
将map遍历时绑定的key的值改为不是动态变化的值(例如index 每一项的索引值,或给每一项设置一个固定的key或id)
原因:
在react中,每一次输入都会触发onChange事件都会重新调用render(),所以每一个item都需要一个唯一的确定的key值,这个key的作用就是避免diff算法重新生成一个全新的dom,所以每当绑定的key变化时diff算法就会生成一个全新的dom,进而导致每次输入都会导致input会失去焦点。