Componentes funcionales con estado vs. sin estado en React

React es una biblioteca de front-end de JavaScript popular para crear interfaces de usuario interactivas. React tiene una curva de aprendizaje relativamente superficial, que es una de las razones por las que está recibiendo toda la atención últimamente. 

Si bien hay muchos conceptos importantes que cubrir, los componentes son innegablemente el corazón y el alma de React. Tener una buena comprensión de los componentes debería facilitarte la vida como desarrollador de React. 

Prerrequisitos

Este tutorial está dirigido a principiantes que han comenzado a aprender React y necesitan una mejor descripción de los componentes. Comenzaremos con los aspectos básicos de los componentes y luego pasaremos a los conceptos más desafiantes, como los patrones de los componentes y cuándo usarlos. Se han cubierto diferentes clasificaciones de componentes, tales como componentes de clase frente a funcionales, componentes de estado frente a sin estado, y componentes de contenedor y presentación.. 

Antes de comenzar, quiero presentarles el fragmento de código que usaremos en este tutorial. Es un contador simple construido con React. Me referiré a algunas partes de este ejemplo a lo largo del tutorial.. 

Entonces empecemos. 

¿Qué son los componentes??

Los componentes son microentidades independientes y autosuficientes que describen una parte de su interfaz de usuario. La IU de una aplicación se puede dividir en componentes más pequeños donde cada componente tiene su propio código, estructura y API. 

Facebook, por ejemplo, tiene miles de piezas de funcionalidad conectadas entre sí cuando ves su aplicación web. Aquí hay un dato interesante: Facebook comprende 30,000 componentes, y el número está creciendo. La arquitectura de componentes le permite pensar en cada pieza de forma aislada. Cada componente puede actualizar todo en su alcance sin preocuparse por cómo afecta a otros componentes. 

Si tomamos la interfaz de usuario de Facebook como ejemplo, la barra de búsqueda sería un buen candidato para un componente. El suministro de noticias de Facebook creará otro componente (o un componente que alberga muchos subcomponentes). Todos los métodos y llamadas AJAX relacionadas con la barra de búsqueda estarían dentro de ese componente.

Los componentes también son reutilizables. Si necesita el mismo componente en varios lugares, eso es fácil. Con la ayuda de la sintaxis JSX, puede declarar sus componentes donde quiera que aparezcan, y eso es todo.. 

 
Cuenta actual: this.state.count
/ * Reutilización de componentes en acción. * /

Apoyos y estado

Los componentes necesitan datos para trabajar. Hay dos formas diferentes de combinar componentes y datos: ya sea como accesorios o estado. los apoyos y el estado determinan qué representa un componente y cómo se comporta. Vamos a empezar con los accesorios.

accesorios

Si los componentes fueran funciones simples de JavaScript, entonces props sería la entrada de la función. Siguiendo esa analogía, un componente acepta una entrada (lo que llamamos accesorios), la procesa y luego procesa un código JSX..

Aunque los datos en accesorios son accesibles a un componente, la filosofía de React es que los accesorios deben ser inmutables y de arriba hacia abajo. Lo que esto significa es que un componente principal puede transmitir los datos que quiera a sus elementos secundarios, pero el componente secundario no puede modificarlos. Por lo tanto, si intentas editar los accesorios como lo hice a continuación, obtendrás el error "No se puede asignar a solo lectura".

botón const = (props) => // props se leen solo props.count = 21;…

Estado

Estado, por otro lado, es un objeto que es propiedad del componente donde se declara. Su alcance está limitado al componente actual. Un componente puede inicializar su estado y actualizarlo cuando sea necesario. El estado del componente padre generalmente termina siendo accesorios del componente hijo. Cuando el estado se pasa fuera del alcance actual, lo llamamos prop..


Ahora que conocemos los componentes básicos, echemos un vistazo a la clasificación básica de los componentes..

Componentes de clase vs. componentes funcionales

Un componente React puede ser de dos tipos: un componente de clase o un componente funcional. La diferencia entre los dos es evidente por sus nombres.. 

Componentes funcionales

Los componentes funcionales son solo funciones de JavaScript. Reciben una entrada opcional que, como he mencionado anteriormente, es lo que llamamos accesorios.


Algunos desarrolladores prefieren usar las nuevas funciones de flecha de ES6 para definir componentes. Las funciones de flecha son más compactas y ofrecen una sintaxis concisa para escribir expresiones de funciones. Al utilizar una función de flecha, podemos omitir el uso de dos palabras clave, función y regreso, y un par de llaves. Con la nueva sintaxis, puede definir un componente en una sola línea como esta. 

const Hola = (nombre) => (
Hola nombre!
);

Componentes de clase

Los componentes de clase ofrecen más funciones, y con más funciones viene más equipaje. La razón principal para elegir componentes de clase sobre componentes funcionales es que pueden tener estado.

La sintaxis state = count: 1 es parte de la característica de campos de clase pública. Más sobre esto abajo. 

Hay dos formas de crear un componente de clase. La forma tradicional es usar React.createClass (). ES6 introdujo una sintaxis de azúcar que le permite escribir clases que se extienden React.Component. Sin embargo, ambos métodos están destinados a hacer lo mismo.. 

Los componentes de clase también pueden existir sin estado. Aquí hay un ejemplo de un componente de clase que acepta una entrada de datos y procesa JSX.

la clase Hello extiende React.Component constructor (props) super (props);  render () return ( 
Hola props
)

Definimos un método constructor que acepta props como entrada. Dentro del constructor, llamamos súper() para pasar todo lo que se hereda de la clase padre. Aquí hay algunos detalles que podrías haber pasado por alto..

Primero, el constructor es opcional mientras define un componente. En el caso anterior, el componente no tiene un estado y el constructor no parece hacer nada útil. esto.props utilizado dentro de la hacer() funcionará independientemente de si el constructor está definido o no. Sin embargo, aquí hay algo de los documentos oficiales:

Los componentes de clase siempre deben llamar al constructor base con accesorios.

Como una buena práctica, recomendaré usar el constructor para todos los componentes de la clase.

En segundo lugar, si está utilizando un constructor, debe llamar súper(). Esto no es opcional, y obtendrá el error de sintaxis "Falta super () llamada constructor" de otra manera. 

Y mi último punto es sobre el uso de súper() vs. super (accesorios). super (accesorios) debe ser usado si vas a llamar esto.props Dentro del constructor. De lo contrario, utilizando súper() solo es suficiente.

Componentes con estado vs. componentes sin estado

Esta es otra forma popular de clasificar componentes. Y el criterio para la clasificación es simple: los componentes que tienen estado y los componentes que no tienen. 

Componentes de estado

Los componentes con estado son siempre componentes de clase. Como se mencionó anteriormente, los componentes con estado tienen un estado que se inicializa en el constructor. 

// Aquí hay un extracto del constructor de ejemplo de contador (props) super (props); this.state = count: 0; 

Hemos creado un objeto de estado y lo hemos inicializado con un conteo de 0. Se ha propuesto una sintaxis alternativa para hacer esto más fácil llamado campos de clase. Aún no es parte de la especificación ECMAScript, pero si está usando un transpiler de Babel, esta sintaxis debería funcionar de inmediato..

la aplicación de la clase extiende el Componente / * // Ya no es necesario constructor () super (); this.state = count: 1 * / state = count: 1; handleCount (valor) this.setState ((prevState) => (count: prevState.count + value));  render () // omitido por brevedad

Puedes evitar usar el constructor en conjunto con esta nueva sintaxis.

Ahora podemos acceder al estado dentro de los métodos de clase incluyendo hacer(). Si vas a usarlos dentro. hacer() para mostrar el valor del recuento actual, debe colocarlo entre corchetes de la siguiente manera:

render () return (cuenta actual: this.state.count)

los esta palabra clave aquí se refiere a la instancia del componente actual. 

Inicializar el estado no es suficiente, necesitamos poder actualizar el estado para crear una aplicación interactiva. Si pensabas que esto funcionaría, no, no funcionará..

// Manera incorrecta handleCount (valor) this.state.count = this.state.count + value; 

 Los componentes de React están equipados con un método llamado setState para actualizar el estado. setState acepta un objeto que contiene el nuevo estado del contar.

// Esto funciona handleCount (value) this.setState (count: this.state.count + value); 

los setState () acepta un objeto como entrada, e incrementamos el valor anterior de contar en 1, que funciona como se esperaba. Sin embargo, hay una trampa. Cuando hay varias llamadas a setState que leen un valor anterior del estado y escriben un nuevo valor en él, podemos terminar con una condición de carrera. Lo que eso significa es que los resultados finales no coincidirán con los valores esperados.

Aquí hay un ejemplo que debería dejarlo claro para usted. Prueba esto en el fragmento de código y caja arriba.

// ¿Cual es la salida esperada? Pruébalo en el código sandbox. handleCount (valor) this.setState (count: this.state.count + 100); this.setState (count: this.state.count + value); this.setState (count: this.state.count-100); 

Queremos que setState incremente el conteo en 100, luego lo actualice en 1 y luego elimine los 100 que se agregaron anteriormente. Si setState realiza la transición de estado en el orden real, obtendremos el comportamiento esperado. Sin embargo, setState es asíncrono y es posible que varias llamadas a setState se agrupen para mejorar la experiencia y el rendimiento de la interfaz de usuario. Así que el código anterior produce un comportamiento que es diferente de lo que esperamos.

Por lo tanto, en lugar de pasar directamente un objeto, puede pasar una función de actualización que tiene la firma:

(prevState, props) => stateChange 

prevState es una referencia al estado anterior y se garantiza que está actualizado. props se refiere a los props del componente, y no necesitamos props para actualizar el estado aquí, por lo que podemos ignorar eso. Por lo tanto, podemos usarlo para actualizar el estado y evitar la condición de carrera..

// La forma correcta de handleCount (value) this.setState ((prevState) => count: prevState.count +1); 

los setState () redirige el componente y tiene un componente de estado activo.

Componentes sin estado

Puede utilizar una función o una clase para crear componentes sin estado. Pero a menos que necesite usar un gancho de ciclo de vida en sus componentes, debería elegir componentes funcionales sin estado. Hay muchos beneficios si decide utilizar componentes funcionales sin estado aquí; son fáciles de escribir, entender y probar, y usted puede evitar el esta palabra clave en conjunto. Sin embargo, a partir de React v16, no hay beneficios de rendimiento al usar componentes funcionales sin estado en lugar de componentes de clase. 

La desventaja es que no puedes tener ganchos de ciclo de vida. El método del ciclo de vida. ShouldComponentUpdate () a menudo se utiliza para optimizar el rendimiento y controlar manualmente lo que se vuelve a enviar. Aún no puedes usar eso con componentes funcionales. Refs también no son compatibles.

Componentes de contenedores vs. componentes de presentación

Este es otro patrón que es muy útil al escribir componentes. El beneficio de este enfoque es que la lógica de comportamiento está separada de la lógica de presentación.

Componentes de presentación

Los componentes de presentación se combinan con la vista o cómo se ven las cosas. Estos componentes aceptan accesorios de su contraparte del contenedor y los representan. Todo lo que tiene que ver con describir la interfaz de usuario debe ir aquí.. 

Los componentes de la presentación son reutilizables y deben permanecer desacoplados de la capa de comportamiento. Un componente de presentación recibe los datos y devoluciones de llamada exclusivamente a través de accesorios y, cuando se produce un evento, como un botón que se presiona, realiza una devolución de llamada al componente contenedor a través de accesorios para invocar un método de manejo de eventos. 

Los componentes funcionales deben ser su primera opción para escribir componentes de presentación a menos que se requiera un estado. Si un componente de presentación requiere un estado, debe ocuparse del estado de la interfaz de usuario y no de los datos reales. El componente de presentación no interactúa con la tienda Redux ni hace llamadas a la API. 

Componentes de contenedores

Los componentes del contenedor se ocuparán de la parte de comportamiento. Un componente contenedor le dice al componente de presentación lo que se debe representar utilizando props. No debe contener marcas y estilos de DOM limitados. Si está utilizando Redux, un componente contenedor contiene el código que envía una acción a una tienda. Alternativamente, este es el lugar donde debe realizar sus llamadas a la API y almacenar el resultado en el estado del componente. 

La estructura habitual es que hay un componente contenedor en la parte superior que pasa los datos a sus componentes de presentación secundarios como accesorios. Esto funciona para proyectos más pequeños; sin embargo, cuando el proyecto se haga más grande y tenga muchos componentes intermedios que solo acepten accesorios y los pasen a los componentes secundarios, esto se volverá desagradable y difícil de mantener. Cuando esto sucede, es mejor crear un componente contenedor único para el componente de hoja, y esto aliviará la carga de los componentes intermedios.

Entonces, ¿qué es un PureComponent?

Llegará a escuchar el término componente puro muy a menudo en los círculos React, y luego está React.PureComponent. Cuando eres nuevo en React, todo esto puede parecer un poco confuso. Se dice que un componente es puro si se garantiza que devolverá el mismo resultado dados los mismos apoyos y estado. Un componente funcional es un buen ejemplo de un componente puro porque, dada una entrada, usted sabe qué se procesará. 

const HelloWorld = (name) => ( 
'Hola $ nombre'
);

Los componentes de clase también pueden ser puros siempre que sus propiedades y estado sean inmutables. Si tienes un componente con un conjunto de propiedades y estado inmutables 'profundos', React API tiene algo que se llama PureComponent. React.PureComponent es parecido a React.Component, pero implementa el ShouldComponentUpdate () método un poco diferente. ShouldComponentUpdate () Se invoca antes de que algo sea reenviado. El comportamiento predeterminado es que devuelve verdadero, de modo que cualquier cambio en el estado o en las propiedades vuelve a representar el componente..

shouldComponentUpdate (nextProps, nextState) return true; 

Sin embargo, con PureComponent, realiza una comparación superficial de objetos. La comparación superficial significa que se comparan los contenidos inmediatos de los objetos en lugar de comparar recursivamente todos los pares clave / valor del objeto. Por lo tanto, solo se comparan las referencias de los objetos, y si el estado / accesorios están mutados, esto podría no funcionar como se esperaba.. 

React.PureComponent se utiliza para optimizar el rendimiento, y no hay ninguna razón por la que deba considerar su uso a menos que encuentre algún tipo de problema de rendimiento. 

Pensamientos finales

Los componentes funcionales sin estado son más elegantes y, por lo general, son una buena opción para construir los componentes de presentación. Debido a que solo son funciones, no tendrá dificultades para escribirlas y comprenderlas y, además, son fáciles de probar.. 

Cabe señalar que los componentes funcionales sin estado no tienen la ventaja en términos de optimización y rendimiento porque no tienen una ShouldComponentUpdate () gancho. Esto podría cambiar en versiones futuras de React, donde los componentes funcionales podrían optimizarse para un mejor rendimiento. Sin embargo, si no es crítico con el rendimiento, debe atenerse a los componentes funcionales para la vista / presentación y los componentes de clase con estado para el contenedor..

Con suerte, este tutorial le ha brindado una descripción general de alto nivel de la arquitectura basada en componentes y diferentes patrones de componentes en React. ¿Qué piensas sobre esto? Compártelos a través de los comentarios..

En los últimos años, React ha crecido en popularidad. De hecho, tenemos una serie de artículos en Envato Market que están disponibles para su compra, revisión, implementación, etc. Si busca recursos adicionales en React, no dude en consultarlos..