Formik FieldArray中TextField输入单字符即失焦问题排查
问题原因
输入单字符就失焦的核心原因是每次输入触发表单状态更新、组件重渲染时,React判定输入框对应的DOM节点被销毁重建,焦点自然丢失。你配置key的方式存在明显错误,是触发这个问题的直接诱因:
- 错误使用数组下标
index作为列表项key:从FieldArray判断你用的是Formik表单库,输入时表单状态更新会生成新的状态引用,用下标作为key时,React的diff算法无法稳定匹配上一次渲染的对应输入框节点,会直接销毁旧节点创建新节点。 - 冗余key配置干扰diff逻辑:你在多层嵌套的Grid组件、甚至包裹整个列表的容器div上都加了key属性,尤其是外层容器的
key={myIndex},一旦传入的myIndex或相关引用变动,整个列表容器会被直接卸载重建,所有输入框都会失焦。内层重复配置的key={index}也会干扰React对节点匹配的判断。 - 额外高频踩坑点:如果
MyValues组件是定义在其他组件的函数作用域内部,每次父组件重渲染都会重新生成MyValues的组件引用,会导致整个组件树完全重挂载,必然丢焦点。
修复方式
- 给
myValues数组的每一项配置稳定唯一标识(比如新增选项时生成时间戳/随机字符串作为id),遍历map时只用这个唯一id作为列表最外层元素的key,不要用数组下标。 - 删掉所有非列表直接子元素上的冗余key属性:包括外层列表容器上的
key={myIndex}、内层Grid组件上重复添加的key={index},key只需要加在map遍历返回的第一个外层元素上即可。 - 把
MyValues组件的定义提到父组件作用域外,保证组件引用稳定,不要嵌套在其他组件内部定义。 - 涉及数组增删操作时,通过唯一id定位对应项的索引,不要直接依赖遍历时候的index,避免操作错位。
修复后的参考代码:
// MyValues 定义在组件作用域外,保证引用稳定 const MyValues = ({ myGroup, name }) => ( <FieldArray name={name} render={(arrayHelpers) => ( <> <div className={classes.dataSourceLayout}> {myGroup.myValues.map((myValue) => { // 提前定位当前项索引,供删除、字段名绑定使用 const currentIndex = myGroup.myValues.findIndex(item => item.id === myValue.id) return ( <div key={myValue.id}> <Grid container item spacing={6}> <Grid item container spacing={1}> <Grid item xs={5}> <Select name={`${name}.${currentIndex}.job`} label='Job' options={jobs} /> </Grid> <Grid item xs={5}> <TextField name={`${name}.${currentIndex}.salary`} label='Salary' /> </Grid> <Grid item xs={2}> {myGroup.myValues.length > 1 && ( <Button disableElevation onClick={() => arrayHelpers.remove(currentIndex)} > <span>Delete</span> </Button> )} </Grid> </Grid> </Grid> </div> ) })} </div> </> )} /> ); // 新增表单项时记得生成唯一id,示例: // const addNewItem = () => { // arrayHelpers.push({ // id: `salary_item_${Date.now()}`, // job: '', // salary: '' // }) // }
内容的提问来源于stack exchange,提问作者ArthurJ
相关产品推荐
相关产品推荐

