Mejora de la funcionalidad del componente React con React.memo ()

Le presentamos una traducci贸n del art铆culo de Chidume Nnamdi, que se public贸 en blog.bitsrc.io. Si desea aprender c贸mo evitar renderizaciones innecesarias y lo 煤tiles que son las nuevas herramientas en React, bienvenido a cat.



El equipo React.js est谩 trabajando duro para hacer que React se ejecute lo m谩s r谩pido posible. Para permitir a los desarrolladores acelerar sus aplicaciones React, se han agregado las siguientes herramientas:

  • React. Perezoso y suspenso para carga de componentes retrasada;
  • Componente puro
  • los ganchos del ciclo de vida debenComponentUpdate (...) {...}.

En este art铆culo, consideraremos, entre otras, otra herramienta de optimizaci贸n agregada en React v16.6 para acelerar las funciones de los componentes: React.memo .

Consejo: Use Bit para instalar y compartir componentes React. Use sus componentes para crear nuevas aplicaciones y compartirlas con el equipo para acelerar las cosas. 隆Pru茅balo!



Render extra


En React, cada componente corresponde a una unidad de vista. Los componentes tambi茅n tienen estados. Cuando el valor del estado cambia debido a las acciones del usuario, el componente se da cuenta de que se necesita volver a dibujar. El componente Reaccionar se puede volver a dibujar cualquier cantidad de veces. En algunos casos, esto es necesario, pero la mayor铆a de las veces puede prescindir de un renderizador, especialmente porque ralentiza enormemente la aplicaci贸n.

Considere el siguiente componente:

import React from 'react'; class TestC extends React.Component { constructor(props) { super(props); this.state = { count: 0 } } componentWillUpdate(nextProps, nextState) { console.log('componentWillUpdate') } componentDidUpdate(prevProps, prevState) { console.log('componentDidUpdate') } render() { return ( <div > {this.state.count} <button onClick={()=>this.setState({count: 1})}>Click Me</button> </div> ); } } export default TestC; 

El valor inicial del estado {count: 0} es 0. Si hace clic en el bot贸n Click me, el estado del conteo se convertir谩 en 1. En nuestra pantalla, 0 tambi茅n cambiar谩 a 1. Pero si hacemos clic nuevamente en el bot贸n, comienzan los problemas: el componente no se debe volver a dibujar, porque La condici贸n no ha cambiado. El valor del contador "a" es 1, el nuevo valor tambi茅n es uno, lo que significa que no hay necesidad de actualizar el DOM.

Para ver la actualizaci贸n de nuestro TestC, en el que se establece el mismo estado dos veces, agregu茅 dos m茅todos de ciclo de vida. React inicia el ciclo componentWillUpdate cuando el componente se actualiza / redibuja debido a un cambio de estado. El ciclo componentdidUpdate React comienza cuando un componente se procesa correctamente.

Si lanzamos el componente en el navegador e intentamos hacer clic en el bot贸n Hacer clic varias veces, obtenemos el siguiente resultado:



La repetici贸n de la entrada componentWillUpdate en nuestra consola indica que el componente se vuelve a dibujar incluso cuando el estado no cambia. Este es un render extra.

Componente puro / shouldComponentUpdate


El enlace del ciclo de vida shouldComponentUpdate ayudar谩 a evitar la representaci贸n innecesaria en los componentes React.

React inicia el m茅todo shouldComponentUpdate al comienzo de la representaci贸n del componente y recibe una luz verde de este m茅todo para continuar el proceso o una se帽al de que el proceso est谩 inhibido .

Deje que deber铆a deber铆a ser nuestro UpdateComponentUpdate as铆:

 shouldComponentUpdate(nextProps, nextState) { return true } 

  • nextProps : el siguiente valor de props que recibir谩 el componente;
  • nextState : el siguiente valor de state que recibir谩 el componente.

Entonces permitimos que React represente el componente porque el valor de retorno es true .

Supongamos que escribimos lo siguiente:

 shouldComponentUpdate(nextProps, nextState) { return false } 

En este caso, prohibimos que React procese el componente, porque false devuelve false .
De lo anterior se deduce que para renderizar el componente necesitamos devolver true . Ahora podemos reescribir el componente TestC de la siguiente manera:

 import React from 'react'; class TestC extends React.Component { constructor(props) { super(props); this.state = { count: 0 } } componentWillUpdate(nextProps, nextState) { console.log('componentWillUpdate') } componentDidUpdate(prevProps, prevState) { console.log('componentDidUpdate') } shouldComponentUpdate(nextProps, nextState) { if (this.state.count === nextState.count) { return false } return true } render() { return ( <div> { this.state.count } <button onClick = { () => this.setState({ count: 1 }) }> Click Me </button> </div> ); } } export default TestC; 

Agregamos un enlace shouldComponentUpdate al componente TestC. Ahora el valor de count en el objeto de estado actual this.state.count compara con el valor de count en el siguiente objeto de estado nextState.count . Si son iguales === , no se vuelve a dibujar y false devuelve false . Si no son iguales, true devuelve true y se inicia un renderizador para mostrar el nuevo valor.

Si probamos el c贸digo en un navegador, veremos un resultado familiar:



Pero al hacer clic en el bot贸n Click Me clic varias veces, todo lo que vemos es lo siguiente (隆se muestra solo una vez!):

componentWillUpdate
componentDidUpdate




Puede cambiar el estado del componente TestC en la pesta帽a React DevTools. Haga clic en la pesta帽a Reaccionar, seleccione TestC a la derecha y ver谩 el valor del estado del contador:



Este valor puede ser cambiado. Haga clic en el texto del contador, escriba 2 y presione Entrar.



El estado del conteo cambiar谩 y en la consola veremos:

 componentWillUpdate componentDidUpdate componentWillUpdate componentDidUpdate 



El valor anterior era 1 y el nuevo era 2, por lo que era necesario volver a dibujar.
Pasemos al componente puro .

Pure Component apareci贸 en React en la versi贸n v15.5. Se utiliza para comparar valores predeterminados ( change detection ). Usando extend React.PureComponent , no tiene que agregar el m茅todo del ciclo de vida shouldComponentUpdate a los componentes: el seguimiento de cambios ocurre por s铆 mismo.

Agregue un PureComponent al componente TestC.

 import React from 'react'; class TestC extends React.PureComponent { constructor(props) { super(props); this.state = { count: 0 } } componentWillUpdate(nextProps, nextState) { console.log('componentWillUpdate') } componentDidUpdate(prevProps, prevState) { console.log('componentDidUpdate') } /*shouldComponentUpdate(nextProps, nextState) { if (this.state.count === nextState.count) { return false } return true }*/ render() { return ( <div> { this.state.count } <button onClick = { () => this.setState({ count: 1 }) }> Click Me </button> </div > ); } } export default TestC; 

Como puede ver, shouldComponentUpdate en un comentario. Ya no lo necesitamos: todo el trabajo lo realiza React.PureComponent .

Al reiniciar el navegador para probar la nueva soluci贸n, y al hacer clic en el bot贸n Click Me clic varias veces, obtenemos:





Como puede ver, solo apareci贸 una entrada de component*Update en la consola.

Despu茅s de ver c贸mo trabajar en React con redibujar en las clases de componentes de ES6, pasamos a las funciones de los componentes. 驴C贸mo lograr los mismos resultados con ellos?

Componentes de funciones


Ya sabemos c贸mo optimizar el trabajo con clases usando el componente Pure y el shouldComponentUpdate ciclo de vida shouldComponentUpdate . Nadie argumenta que los componentes de clase son los componentes principales de React, pero puede usar funciones como componentes.

 function TestC(props) { return ( <div> I am a functional component </div> ) } 

Es importante recordar que los componentes de la funci贸n, a diferencia de los componentes de la clase, no tienen estado (aunque ahora que han useState ganchos de useState , esto puede discutirse), lo que significa que no podemos configurar su redibujo. Los m茅todos de ciclo de vida que utilizamos al trabajar con clases no est谩n disponibles aqu铆. Si podemos agregar ganchos de ciclo de vida a los componentes de la funci贸n, podemos agregar el m茅todo shouldComponentUpdate para decirle a React que se necesita un procesador de funciones. (Quiz谩s el autor cometi贸 un error de hecho en la 煤ltima oraci贸n. - Aprox. Ed.) Y, por supuesto, no podemos usar extend React.PureComponent .

Convertimos nuestra clase de componente ES6 TestC en una funci贸n de componente.

 import React from 'react'; const TestC = (props) => { console.log(`Rendering TestC :` props) return ( <div> {props.count} </div> ) } export default TestC; // App.js <TestC count={5} /> 

Despu茅s de renderizar en la consola, vemos la entrada Rendering TestC :5 .



Abra DevTools y haga clic en la pesta帽a Reaccionar. Aqu铆 intentaremos cambiar el valor de las propiedades del componente TestC. Seleccione TestC, y las propiedades del contador con todas las propiedades y valores de TestC se abrir谩n a la derecha. Solo vemos el contador con el valor actual de 5.

Haga clic en el n煤mero 5 para cambiar el valor. En su lugar, aparecer谩 una ventana de entrada.



Si cambiamos el valor num茅rico y presionamos Enter, las propiedades del componente cambiar谩n de acuerdo con el valor que ingresamos. Supongamos que a los 45.



Vaya a la pesta帽a Consola.



El componente TestC se volvi贸 a dibujar porque el valor anterior de 5 cambi贸 al actual - 45. Vuelva a la pesta帽a Reaccionar y cambie el valor a 45, luego regrese a la Consola.



Como puede ver, el componente se vuelve a dibujar, aunque los valores anteriores y nuevos son los mismos. :(

驴C贸mo gestionar un renderizador?

Soluci贸n: React.memo ()


React.memo() es una nueva caracter铆stica introducida en React v16.6. Su principio de funcionamiento es similar al principio de React.PureComponent : ayuda en la gesti贸n del redise帽o de funciones de componentes. React.memo(...) para componentes de clase es React.PureComponent para componentes de funci贸n.

驴C贸mo trabajar con React.memo (...)?
Bastante simple Digamos que tenemos una funci贸n componente.

 const Funcomponent = ()=> { return ( <div> Hiya!! I am a Funtional component </div> ) } 

Solo necesitamos pasar FuncComponent como argumento para la funci贸n React.memo.

 const Funcomponent = ()=> { return ( <div> Hiya!! I am a Funtional component </div> ) } const MemodFuncComponent = React.memo(FunComponent) 

React.memo devuelve MemodFuncComponent purified MemodFuncComponent . Esto es lo que dibujaremos en el marcado JSX. Cuando las propiedades y el estado de un componente cambian, React compara las propiedades y estados anteriores y actuales del componente. Y solo si no son id茅nticos, la funci贸n componente se vuelve a dibujar.

Aplique esto al componente de funci贸n TestC.

 let TestC = (props) => { console.log('Rendering TestC :', props) return ( <div> { props.count } </> ) } TestC = React.memo(TestC); 

Abra un navegador y descargue la aplicaci贸n. Abra DevTools y vaya a la pesta帽a Reaccionar. Seleccione <Memo(TestC)> .

Si en el bloque de la derecha cambiamos las propiedades del contador a 89, la aplicaci贸n se volver谩 a dibujar.



Si cambiamos el valor al anterior, 89, entonces ...



隆No habr谩 redibujos!

Gloria a reaccionar.memo (...)! :)

Sin usar React.memo(...) en nuestro primer ejemplo, la funci贸n del componente TestC se vuelve a dibujar incluso cuando el valor anterior cambia a uno id茅ntico. Ahora, gracias a React.memo(...) , podemos evitar la representaci贸n innecesaria de las funciones de los componentes.

Conclusi贸n


  • Vamos a repasar la lista?
  • React.PureComponent - plata;
  • React.memo(...) - oro;
  • React.PureComponent funciona con clases ES6;
  • React.memo(...) funciona con funciones;
  • React.PureComponent optimiza el redise帽o de las clases ES6;
  • React.memo(...) optimiza el redise帽o de la funci贸n;
  • la optimizaci贸n de funciones es una idea excelente;
  • React nunca volver谩 a ser lo mismo.

Si tiene alguna pregunta sobre el art铆culo o cualquier informaci贸n adicional, cambios u objeciones, no dude en escribirme comentarios, correos electr贸nicos o mensajes privados.

Gracias

Source: https://habr.com/ru/post/442116/


All Articles