Re-renderizações desnecessárias de TextField
Percebi um problema em que todos os componentes do mesmo pai ( App no exemplo abaixo) serão renderizados novamente quando os estados / props não relacionados mudarem, tornando a página / formulários perceptíveis mais lentos.
Eu segui muitos conselhos, como memorizar manipuladores de eventos e adereços, mas componentes não relacionados ainda são renderizados novamente. Estou perplexo. O que não estou entendendo sobre React?
[ CodeSandbox ] No depurador React, habilitar: Destacar atualizações quando os componentes forem renderizados
import React, { useMemo, useState } from "react";
import { TextField } from "@material-ui/core";
function MyTextInput(props) {
return (
<TextField
variant={"outlined"}
onChange={props.onChange}
value={props.value}
/>
);
}
export default function App() {
const [exampleTextValue1, setExampleTextValue1] = useState("");
const [exampleTextValue2, setExampleTextValue2] = useState("");
const handleChange1 = useMemo(
() => (event) => setExampleTextValue1(event.target.value),
[]
);
const handleChange2 = useMemo(
() => (event) => setExampleTextValue2(event.target.value),
[]
);
return (
<>
<div>
Change me:
<MyTextInput value={exampleTextValue1} onChange={handleChange1} />
</div>
<div>
Unrelated inputs. Should not re-render:
<MyTextInput value={exampleTextValue2} onChange={handleChange2} />
<MyTextInput value={exampleTextValue2} onChange={handleChange2} />
{/* to feel the impact, copy the above line like 98 more times */}
</div>
</>
);
}
Respostas
As ferramentas do depurador são bugadas em relação aos componentes memoized. Quando você memoriza os componentes, eles não são realmente renderizados, mas as ferramentas de depuração os destacam de qualquer maneira (vejahttps://github.com/facebook/react/issues/19778)
Para realmente testar a re-renderização, altere o valor de estado padrão para a segunda entrada (que é renderizada muitas vezes) para algo como "teste", em seguida, coloque um console.logdentro de um MyTextInputcomponente memoizado para ver quais estão realmente sendo renderizados novamente:
const MyTextInput = React.memo((props) => {
console.log(props.value);
return (
<TextField
variant={"outlined"}
onChange={props.onChange}
value={props.value}
disabled={props.disabled}
/>
);
});
Você pode ver que ele imprime o valor de "teste" uma vez para todas as segundas entradas quando elas são renderizadas pela primeira vez, então, conforme você digita a primeira, não está registrando todas as segundas entradas console.loggraças à memoização.