React+MUI项目:解决表格内TextField编辑时失焦的问题
解决MUI表格中TextField编辑时失焦问题
我在开发一款HR网页应用的问卷创建功能,用MUI组件实现了展示问卷问题的表格,支持修改问题文本,但遇到一个问题:每次编辑TextField时,输入框都会失去焦点,仅在TextField嵌套于表格内时出现这个现象。
相关代码如下:
import TableContainer from "@mui/material/TableContainer"; import Table from "@mui/material/Table"; import TableBody from "@mui/material/TableBody"; import TableRow from "@mui/material/TableRow"; import TableCell from "@mui/material/TableCell"; import TextField from "@mui/material/TextField"; import { styled } from "@mui/system"; import { useState } from "react"; export default function TableTextFieldTest() { const [questions, setQuestions] = useState([ { index: 0, question: "Do you have any feedback on your manager or team that you'd like to share?", }, { index: 1, question: "What suggestions do you have for improving the company culture or work environment?", }, { index: 2, question: "How was your experience working here?", } ]); //Custom style elements const TableBodyCell = styled(TableCell)({ paddingLeft: "24px", paddingRight: "24px", paddingTop: "16px", paddingBottom: "16px" }); //Handle changes to the textfield when editing a survey question function handleEditTextfield(e, index) { const newQuestions = Array.from(questions); const q = newQuestions.find((q) => q.index === index); q.question = e.target.value; setQuestions(newQuestions); }; return ( <TableContainer> <Table> <TableBody> {questions.sort((q1, q2) => q1.index - q2.index).map((q, index) => ( <TableRow> <TableBodyCell> <TextField value={q.question} onChange={(e) => handleEditTextfield(e, index)} sx={{ width: "100%" }} /> </TableBodyCell> </TableRow> ))} </TableBody> </Table> </TableContainer> ); };
问题原因
- 不稳定的key值:
map遍历依赖数组索引作为隐式key,每次修改问题触发state更新后,sort操作会改变数组元素顺序,导致React无法识别组件的稳定性,强制重新渲染并丢失焦点。 - 内部定义的styled组件:
TableBodyCell定义在组件内部,每次组件渲染都会重新创建这个styled组件,React会认为这是全新的组件类型,卸载旧组件并挂载新组件,直接导致焦点丢失。 - 索引匹配错误:
handleEditTextfield中传入的是map的数组索引,但查找时用的是问题对象自身的index属性,当数组排序后两者可能不匹配,导致更新逻辑混乱,间接引发渲染异常。
解决方案
- 使用稳定的key:给
TableRow设置唯一且稳定的key,直接使用问题对象的index属性(确保其唯一性)。 - 将styled组件移到外部:把
TableBodyCell定义在组件外部,避免每次渲染重新创建。 - 修正索引传递:在
onChange中传递问题对象的index属性,而非map的数组索引,确保更新逻辑准确。
修改后的完整代码
import TableContainer from "@mui/material/TableContainer"; import Table from "@mui/material/Table"; import TableBody from "@mui/material/TableBody"; import TableRow from "@mui/material/TableRow"; import TableCell from "@mui/material/TableCell"; import TextField from "@mui/material/TextField"; import { styled } from "@mui/system"; import { useState } from "react"; // 将styled组件移到组件外部 const TableBodyCell = styled(TableCell)({ paddingLeft: "24px", paddingRight: "24px", paddingTop: "16px", paddingBottom: "16px" }); export default function TableTextFieldTest() { const [questions, setQuestions] = useState([ { index: 0, question: "Do you have any feedback on your manager or team that you'd like to share?", }, { index: 1, question: "What suggestions do you have for improving the company culture or work environment?", }, { index: 2, question: "How was your experience working here?", } ]); function handleEditTextfield(e, questionIndex) { const newQuestions = [...questions]; // 用展开运算符更简洁 const q = newQuestions.find((q) => q.index === questionIndex); if (q) { // 增加判断避免找不到的情况 q.question = e.target.value; setQuestions(newQuestions); } }; return ( <TableContainer> <Table> <TableBody> {questions.sort((q1, q2) => q1.index - q2.index).map((q) => ( <TableRow key={q.index}> {/* 使用稳定的key */} <TableBodyCell> <TextField value={q.question} onChange={(e) => handleEditTextfield(e, q.index)} {/* 传递问题自身的index */} sx={{ width: "100%" }} /> </TableBodyCell> </TableRow> ))} </TableBody> </Table> </TableContainer> ); };
内容的提问来源于stack exchange,提问作者Gabriel Chan
相关产品推荐
相关产品推荐

