Los componentes de orden superior (HOC) son un tipo de componente de React que le ayuda a reutilizar la lógica en su aplicación. La terminología puede parecer compleja, pero los HOC son fáciles de administrar y pueden simplificar el mantenimiento de la base del código.
UN Componente de orden superior siempre envuelve los componentes secundarios con funcionalidad adicional. Un HOC se define como una función que toma un componente como parámetro. Luego devuelve un archivo nuevo componente, que normalmente hará que el componente de entrada esté envuelto con accesorios adicionales.
Un simple ejemplo
La mejor manera de apreciar cuando los HOC tienen sentido es verlos en acción. Consideremos un sistema de pago simple donde el estado del carrito del usuario se almacena de forma centralizada dentro de la aplicación. Nuestros ejemplos muestran Redux como un archivo estatal, pero solo con fines ilustrativos.
Supongamos que este objeto representa el estado de nuestra aplicación:
{ checkout: { items: [ { label: "Product 1", price: 150.00, quantity: 2 }, { label: "Product 2", price: 75.00, quantity: 1 } ] } }
Tenemos una matriz simple que representa los artículos en el carrito del usuario. Nuestros componentes de pago extraerán valores adicionales de este estado, como el valor total del pedido y los impuestos aplicables.
Nuestro sistema de pago probablemente tendrá que mostrar el valor total dentro de múltiples componentes independientes. Puede haber un widget de barra lateral que muestre el carrito, una pantalla de revisión posterior al pago y una calculadora de costos de envío. Un sistema ingenuo que simplemente pasara los artículos de pago como accesorios correría el riesgo de duplicar la lógica: cada componente tendría que calcular el valor total del pedido por sí mismo.
Presentación de HOC
Echemos un vistazo a cómo puede ayudar un HOC:
import React from "react"; import {connect} from "react-redux"; const withCheckout = ComponentToWrap => { const ComponentWithCheckout = class extends React.Component { render() { return ( <ComponentToWrap checkoutItems={this.props.checkout.items} checkoutTotal={this.total} {...this.props} /> ); } get total() { const prices = this.props.checkout.items.map(i => (i.quantity * i.price)); return prices.reduce((a, b) => (a + b), 0); } } return connect(({checkout}) => ({checkout}))(ComponentWithCheckout); } export default withCheckout;
El archivo exporta una sola función, withCheckout
, que toma un componente React como único parámetro (ComponentToWrap
). Dentro de la función, creamos una nueva clase anónima que es en sí misma un componente de React.
Este nuevo componente es render
el método crea una instancia de ComponentToWrap
pasamos a la función. Ahora tenemos la oportunidad de definir los accesorios de la instancia. Reenviamos el conjunto de elementos de pago como checkoutItems
y hacer que el valor total precalculado esté disponible como checkoutTotal
.
Todos los accesorios que se pasan al HOC se envían al componente interno, lo que garantiza que reciba todos los datos necesarios. La función devuelve la clase anónima recién creada que está lista para ser renderizada en toda la aplicación.
Usamos el connect
método de react-redux
entonces el checkout
prop dentro del HOC recibe el valor de checkout
clave en el estado de nuestra tienda Redux. Este es un detalle de implementación: su HOC puede mantener su estado o comunicarse con otro servicio dentro de la aplicación.
Usando el HOC
Ahora es el momento de utilizar nuestro HOC.
import React from "react"; import withCheckout from "./withCheckout.js"; class CheckoutReviewScreen extends React.Component { render() { return ( <h1>Checkout</h1> <h2>{this.props.checkoutTotal}</h2> ); } } export default withCheckout(CheckoutReviewScreen);
Asumimos lo nuestro withCheckout
HOC se guarda en withCheckout.js
en el mismo directorio que nuestro nuevo componente de pantalla de pago. Envolviendo el componente con nuestro withCheckout
HOC, podemos acceder y ver el valor total del pedido. No necesitamos calcularlo nosotros mismos ni almacenarlo en el estado de la aplicación. Si alguna vez queremos actualizar cómo se calcula el total (por ejemplo, para agregar una tarifa de manejo fija), solo necesitamos hacer el cambio en un lugar, dentro de nuestro HOC.
Ahora puedes renderizar <CheckoutReviewScreen />
en cualquier lugar de su aplicación. Nuestro ejemplo empaquetado no necesita recibir ningún apoyo, ya que obtiene sus datos de nuestra tienda Redux. Porque esta envuelto con withCheckout
, envuelto a su vez con Redux's connect
, la pantalla de revisión recibe automáticamente un archivo checkoutTotal
prop que suma los precios de todos los artículos en el estado de la aplicación.
Ahora vale la pena mencionar lo que llamamos nuestro HOC: withCheckout
. Por convención, los nombres HOC suelen tener una extensión with
prefijo porque agregan algo a los componentes que envuelven. En nuestro caso, el HOC proporciona un acceso conveniente a nuestro carrito de pago que, de lo contrario, necesitaríamos implementar dentro de cada componente.
Ventajas de los HOC
El uso de un HOC le permite abstraer comportamientos comunes de los componentes, minimizando la duplicación de código y aumentando la capacidad de mantenimiento. Los HOC permiten una forma de inyección de dependencia. Le ayudan a mantener sus componentes más simples al permitir el paso de otros componentes del mundo exterior.
Los HOC son comunes dentro del ecosistema React. De hecho, vimos uno en este artículo: connect()
, parte de react-redux
, que suscribe sus componentes a los cambios de estado de Redux.
Los HOC son populares porque proporcionan un método de reutilización de código que no rompe la autocontención de los componentes. El patrón utiliza la capacidad de composición de React para permitirle agregar funcionalidad adicional sin el riesgo de efectos secundarios.
Puede pasar cualquier componente de su aplicación a withCheckout
sin romper nada: el HOC solo ataca unos pocos accesorios extra. Por eso es tan importante que sus HOC reenvíen todas los accesorios que reciben{...this.props}
en nuestro ejemplo). No deben hacer nada que pueda interferir con el funcionamiento normal del componente envuelto.
Puede parecer que sus componentes ahora dependen de su HOC. Este no es el caso. Puede exportar una segunda versión del componente que no está empaquetado, dando a los consumidores la opción de cuál usar.
Su componente en realidad solo insiste en recibir ciertos accesorios: checkoutTotal
Yo nuestro caso. Esto podría ser proporcionado por el HOC o pasando un valor dondequiera que se represente el componente. Nuestro HOC simplifica el desarrollo, pero no ha cambiado fundamentalmente la naturaleza de nuestros componentes renderizados.
Deja una respuesta