likes
comments
collection
share

react中 input中输入后自动失去焦点

作者站长头像
站长
· 阅读数 473

问题

小组小伙伴开发过程中,遇到遍历 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}`}