Material-ui TextField重新渲染后失焦,如何解决该问题?
问题原因分析
TextField失焦的核心原因
遍历渲染数组元素时没有为每个TextField设置稳定唯一的key属性:React的列表重渲染逻辑依赖key判断组件是否可复用,缺少稳定key的情况下,状态更新后React会判定所有TextField都是新组件,直接销毁旧组件并重建新组件,原有输入框的焦点就会丢失。
同时你在onChange中直接修改原状态数组sections[ind] = el属于违反React不可变更新原则的操作,会进一步干扰diff判断,提高组件销毁重建的概率。
TextareaAutosize未出现失焦的原因
TextareaAutosize是Material-UI对原生<textarea>标签的轻量封装,组件结构非常简单,diff识别成本极低;而TextField是复合组件,内部封装了标签、输入框、辅助提示等多个子组件,结构更复杂,在缺少稳定key的场景下,React diff算法对复合组件的复用判断准确率远低于简单组件,因此不会轻易触发销毁重建,也就没有失焦问题。
修复方案
步骤1:为列表项添加稳定唯一的key
首先为每个section项新增唯一业务标识作为key的来源,不要使用数组下标作为key(数组增删时下标会变化,仍属于不稳定key):
// 修改状态初始化代码,新增id字段作为唯一标识 const [sections, setSections] = useState([ { id: 1, Title: "Introduction", Text: "" }, { id: 2, Title: "Relationship", Text: "" }, { id: 3, Title: "Monitoring", Text: "" } ]);
遍历渲染时为列表根节点绑定key:
sections.map((el, ind) => ( // 用稳定的id作为key <div key={el.id}> {/* 原有TextField、TextareaAutosize代码 */} </div> ))
步骤2:修改onChange为不可变更新写法
删除直接修改原状态数组的逻辑,采用React推荐的不可变更新方式更新状态:
TextField的onChange修改为:
onChange={(event) => { setSections(prevSections => prevSections.map((item, i) => i === ind ? {...item, Title: event.target.value} : item )) }}
TextareaAutosize的onChange修改为:
onChange={(event) => { setSections(prevSections => prevSections.map((item, i) => i === ind ? {...item, Text: event.target.value} : item )) }}
修改完成后TextField就不会再出现输入失焦的问题。
内容的提问来源于stack exchange,提问作者Borislav Stefanov
相关产品推荐
相关产品推荐

