MUI自定义Tooltip包裹TextField时状态变更触发失焦问题求助
问题根因
你遇到的问题核心原因是自定义Tooltip组件CustomWidthTooltip被定义在了App组件的内部:
- 每次在TextField输入内容触发
formData状态更新时,整个App组件都会重新渲染 - 组件重渲染时会重新生成一个全新的
CustomWidthTooltip构造函数,React会判定这是不同类型的组件,因此会卸载旧的Tooltip及其内部的所有子组件,再挂载新的Tooltip和子组件 - 原有被卸载的TextField自然会失去焦点,新挂载的TextField默认也不会自动获得焦点,就出现了每次只能输入一个字符的问题
- 未嵌套Tooltip的TextField、以及用官方自带Tooltip的场景不会触发这个问题,是因为这些组件都没有在每次重渲染时被重建
修复方案
把CustomWidthTooltip的定义移到App组件外部即可,修复后的代码如下:
import { useState } from "react"; import { TextField, Box } from "@mui/material"; import { styled } from "@mui/material/styles"; import Tooltip, { tooltipClasses } from "@mui/material/Tooltip"; // 把自定义Tooltip移到组件外部定义,全局仅初始化一次 const CustomWidthTooltip = styled(({ className, ...props }) => ( <Tooltip {...props} classes={{ popper: className }} /> ))({ [`& .${tooltipClasses.tooltip}`]: { maxWidth: 400 } }); export default function App() { const [formData, setFormData] = useState({ title: "", name: "" }); const handleFormChange = (e) => { const { name, value } = e.target; setFormData((formData) => { return { ...formData, [name]: value }; }); }; return ( <Box component="form" display="flex"> <TextField onChange={handleFormChange} autoComplete="title" name="title" id="title" label="Title" required /> <CustomWidthTooltip title="Foo"> <TextField onChange={handleFormChange} autoComplete="name" name="name" id="name" label="Name" required /> </CustomWidthTooltip> </Box> ); }
额外注意事项
- 所有基于MUI
styled生成的自定义组件,都不要放在业务组件内部定义,避免每次重渲染重复生成组件实例导致的卸载重挂载问题 - 如果确实有需要基于组件内部props动态生成样式的场景,可以用styled组件的props传参能力,不要直接把styled定义写在组件内部
内容的提问来源于stack exchange,提问作者alec
相关产品推荐
相关产品推荐

