Estoy usando MUI, y tengo una información sobre herramientas personalizada alrededor de un TextField en un formulario. Tan pronto como escribo algo en ese TextField en particular, pierde el foco. Actualiza el estado de ese valor de mi objeto formData al único carácter que pude escribir, por lo que ese valor solo tiene un carácter de largo. Los otros TextFields en mi formulario funcionan como se esperaba. Si reemplazo la información sobre herramientas personalizada con una estándar, ese TextField en particular también funciona bien. He replicado el problema en codesandbox . Aquí está el código que usé allí:
import { useState } from "react"; import { TextField, Box } from "@mui/material"; import { styled } from "@mui/material/styles"; import Tooltip, { tooltipClasses } from "@mui/material/Tooltip"; export default function App() { const [formData, setFormData] = useState({ title: "", name: "" }); const handleFormChange = (e) => { const { name, value } = e.target; setFormData((formData) => { return { ...formData, [name]: value }; }); }; const CustomWidthTooltip = styled(({ className, ...props }) => ( <Tooltip {...props} classes={{ popper: className }} /> ))({ [`& .${tooltipClasses.tooltip}`]: { maxWidth: 400 } }); return ( <Box component="form" display="flex"> // THIS ONE WORKS JUST FINE <TextField onChange={handleFormChange} autoComplete="title" name="title" id="title" label="Title" required /> // THIS ONE IS BROKEN <CustomWidthTooltip title="Foo"> <TextField onChange={handleFormChange} autoComplete="name" name="name" id="name" label="Name" required /> </CustomWidthTooltip> </Box> ); }¡Gracias por su ayuda, amigos! Los aprecio a todos.
Está inicializando CustomWidthTooltip dentro del componente de la App , lo que hace que la información sobre herramientas se reinicie en el cambio de estado local. Cada vez que el name se actualiza dentro del estado local de formData , el TextField dentro del componente CustomWidthTooltip se vuelve a crear en la interfaz de usuario, lo que provoca la pérdida del foco como resultado.
Debe mover CustomWidthTooltip fuera del componente App .
Updated Code
import "./styles.css"; import { useState } from "react"; import { TextField, Box } from "@mui/material"; import { styled } from "@mui/material/styles"; import Tooltip, { tooltipClasses } from "@mui/material/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: "" }); console.log("formData", formData); const handleFormChange = (e) => { const { name, value } = e.target; console.log({ name, value }); setFormData((formData) => { return { ...formData, [name]: value }; }); }; return ( <div> <h3>With a custom tooltip, it's broken:</h3> <Box component="form" display="flex"> <TextField onChange={handleFormChange} autoComplete="title" name="title" id="title" label="Title" required /> <CustomWidthTooltip title="Custom Custom Custom Custom Custom Custom"> <TextField onChange={handleFormChange} autoComplete="name" name="name" id="name" label="Name" required /> </CustomWidthTooltip> </Box> <h3>With a standard tooltip, it works:</h3> <Box component="form" display="flex"> <TextField onChange={handleFormChange} autoComplete="title" name="title" id="title" label="Title" required /> <Tooltip title="Standard"> <TextField onChange={handleFormChange} autoComplete="name" name="name" id="name" label="Name" required /> </Tooltip> </Box> </div> ); }Como mencionó Junaid, está volviendo a renderizar la información sobre herramientas, por lo que parpadea.
Personalmente, usaría su solución e incluso movería los componentes de estilo personalizado a otro archivo, ya que probablemente querrá reutilizarlos en otro lugar.
Independientemente, otra alternativa es el gancho useMemo . Esta es una buena oportunidad para que usted aprenda cómo puede ayudar.
Puede dejar su función CustomWidthTooltip donde está, pero simplemente envuélvala en useMemo :
import { useState, useMemo } from "react"; ... const CustomWidthTooltip = useMemo( () => styled(({ className, ...props }) => ( <Tooltip {...props} classes={{ popper: className }} /> ))({ [`& .${tooltipClasses.tooltip}`]: { maxWidth: 400 } }), [listOfDependencies] ); ... Entonces, esto calculará el componente con estilo y lo almacenará en su variable, pero no lo recreará en renderizaciones posteriores. La matriz como segundo parámetro ( [listOfDependencies] ), es donde puede agregar variables que debe observar. Si hay algún cambio en estas variables, volverá a calcular CustomWidthTooltip .