Re-renderizaciones innecesarias de TextField

Nov 06 2020

He notado un problema en el que todos los componentes dentro del mismo padre ( aplicación en el ejemplo siguiente) se volverán a procesar cuando cambien los estados / accesorios no relacionados, lo que hace que la página o los formularios sean más lentos.

He seguido muchos consejos, como memorizar controladores de eventos y accesorios, pero los componentes no relacionados aún se vuelven a renderizar. Estoy perplejo. ¿Qué no entiendo sobre React?

[ CodeSandbox ] En el depurador de React, habilite: Resalte las actualizaciones cuando los componentes se procesen

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>
    </>
  );
}

Respuestas

1 Jayce444 Nov 06 2020 at 06:52

Las herramientas de depuración tienen errores con respecto a los componentes memorizados. Cuando memoriza componentes, en realidad no se vuelven a renderizar, pero las herramientas de depuración los resaltan de todos modos (consultehttps://github.com/facebook/react/issues/19778).

Para probar realmente la re-renderización, cambie el valor de estado predeterminado para la segunda entrada (que se renderiza muchas veces) a algo como "prueba", luego coloque un componente console.logmemorizado dentro MyTextInputpara ver cuáles se están volviendo a renderizar:

const MyTextInput = React.memo((props) => {
  console.log(props.value);
  return (
    <TextField
      variant={"outlined"}
      onChange={props.onChange}
      value={props.value}
      disabled={props.disabled}
    />
  );
});

Puede ver que imprime el valor de "prueba" una vez para todas las segundas entradas cuando se procesan por primera vez, luego, mientras escribe la primera, no registra todas las segundas entradas console.loggracias a la memorización.