Quantcast
Channel: Planeta Código
Viewing all articles
Browse latest Browse all 2718

Koalite: Componentes de Orden Superior (Higher Order Components) en ReactJS

$
0
0

Hace tiempo escribí un post sobre cómo utilizar mixins en ReactJS para cargar datos de forma asíncrona. Como pasa con casi cualquier librería de Javascript, un año después los mixins ya no son la forma recomendada de hacer las cosas y ni siquiera están soportados si usas la sintaxis de clases de ES2016.

De todas las alternativas que hay para conseguir implementar lo que antes se hacía con mixins, hay una especialmente interesante. Los componentes de orden superior o higher order components. Incluso si no te interesa mucho ReactJS, la idea que hay detrás te puede resultar útil, por lo que te recomiendo que eches un vistazo a las dos primeras partes de este post.

Funciones de orden superior

El calificativo “de orden superior” se aplica a muchos conceptos. Probablemente te suenen las funciones de orden superior o los tipos de orden superior. Intuitivamente, podríamos decir que algo es “de orden superior” si es capaz de operar sobre cosas de su misma categoría, poniéndose por tanto por encima de ellas.

Un tipo de orden superior es, simplificando bastante, un “tipo de tipos”. Por ejemplo, List<T> en C# sería el tipo de las listas de elementos de tipo T, y como instancias de ese tipo tendríamos List<int> o List<string>.

Una función de orden superior es una función capaz de “trabajar” con funciones. Una función que puede recibir funciones como parámetro o devolverlas como resultado.

Los ejemplos típicos serían el método Enumerable.Select de LINQ en .NET o el método Array.map de Javascript, pero también podemos tenemos funciones que devuelvan otras funciones:

// Función para construir funciones de validación
const maxLength = function(max) {
  return function(value) {
    return value.length <= max;
  };
};

// Función de validación concreta
const isValid = maxLength(4);

isValid('Paco'), // true
isValid('Marcelo'); // false

Hasta aquí, nada raro. Es algo que usamos prácticamente a diario sin reparar en ello, excepto tal vez el último caso que es un poco menos frecuente y, a la vez, más interesante porque...

En Javascript, las clases son funciones

Cuando en Javascript creamos una "clase", aunque usemos la sintaxis de ES2015, en realidad sólo estamos creando una función, por lo que podemos aplicar las mismas ideas que veíamos antes.

// "Clase" para representar coches
const Car = function(brand) {
  this.brand = brand;
};

// Función para crear nuevas clases a partir de otras
// y añadirles una propiedad color
const addColor = function(Class, color) {
  return function() {
    Class.apply(this, arguments);
    this.color = color;
  };
};

// Clase de coches negros
const BlackCar = addColor(Car, 'black');

// Instanciamos un coche negro
const kitt = new BackCar('Pontiac');

kitt.brand === 'Pontiac'
kitt.color === 'black'

Lo interesante no es que le hayamos añadido una propiedad a un objeto (eso se puede hacer de mil forma en Javacript), sino que hemos creado una nueva "clase"BlackCar a partir de una clase que ya existía. Esa lógica de añadir colores a clases que ya existen es completamente reutilizable:

const Food = function(calories) {
  this.calories = calories;
};

var RedFood = addColor(Food, 'red'); 

const tomato = new RedFood(18);
tomato.calories === 18
tomato.color === 'red'

Puesto que la sintaxis de clases de ES2015 no es más que syntactic sugar sobre funciones constructoras, podemos implementar prácticamente lo mismo usando "clases":

class Car {
  constructor(brand) {
    this.brand = brand;
  }
}

const addColor = function(Class, color) {
  return class extends Class {
    constructor(...args) {
      super(...args);
      this.color = color;
    }
  };
}

const BlackCar = addColor(Car, 'black');

const kitt = new BackCar('Pontiac');

kitt.brand === 'Pontiac'
kitt.color === 'black'

Si quieres profundizar en esta idea, te recomiendo encarecidamente que leas este post de Eduard Tomàs sobre clases commo ciudadanos de primer orden en Javascript.

Componentes de orden superior (Higher Order Componentes)

Partiendo de lo que llevamos viendo todo el post y de que los componentes en ReactJS no son más que "clases", está más o menos claro por dónde van los tiros. La idea es poder construir dinámicamente clases de componentes a partir de otros componentes para añadirles comportamiento.

Y ojo, que aquí lo importante es lo de clases de componentes. En ReactJS es normal crear instancias de componentes que están formados por otros componentes, pero ahora lo que haremos es crear un nuevo tipo de componente que podamos instanciar las veces que queramos.

Vamos a ver un ejemplo muy simple.

Imagina que tienes varios componentes que puedena actuar como elementos de un formulario: TextBox, ComboBox, DateTimePicker, etc. Cada uno encapsula el elemento HTML de bajo nivel correspondiente, pero además le añade cierto comportammiento para facilitar su uso, clases css propias de tu aplicación, etc.

Ahora suponte que a veces quieres usar los componentes con su correspondiente <label>, pero en otras ocasiones no lo necesitas y prefieres dejar un simple placeholder. Una forma sencilla de conseguir esto es crear nuevo componente Label que encapsule cada uno de los componentes anteriores:

<Label text='Nombre:'>
  <TextBox onChange={this.updateName} />
</Label>
<Label text='Fecha:'>
  <DateTimePicker onChange={this.updateDate} />
</Label>

Lo malo es que nos obliga a escribir mucho cada vez que queremos añadir una etiqueta a un control. Una alternativa es utilizar componentes de orden superior:

function addLabel(Control) {
  return class extends ReactJS.Component {
    render() {
      return <label>
               {this.props.label}
               <Control {...this.props}/>
             </label>;
    }
  }
}

const LabeledTextBox = addLabel(TextBox);
const LabeledDateTime = addLabel(DateTimePicker);

// El ejemplo anterior quedaría
<LabeledTextBox label='Nombre:' onChange={this.updateName}/>
<LabeledDateTime label='Fecha:' onChange={this.updateDate}/

La función addLabel nos permite crear nuevos tipos de componentes a partir de tipos que ya teníamos. En este caso, podemos añadir una etiqueta a cualquiera de los controles que ya habíamos definido previamente.

Insisto, es importante resaltar que LabeledTextBoxno es una instancia de un componente, si una clase (una función constructora). Por eso podemos usarla con la sintaxis JSX como si fuese una clase definida normalmente.

Con esta técnica podemos simular bastantes de las cosas que hacíamos antes con los mixins, porque podemos encapsular componentes existentes en nuevos componentes que aporten el comportamiento necesario. Por ejemplo, aquí podéis encontrar el escenario típico de carga asíncrona de datos.

Resumen

Javascript es un lenguaje que tiene un montón de pegas. Eso es indudable. Pero también es un lenguaje muy flexible que se basa en un par de ideas muy sencillas sobre las que se pueden construir cosas más entretenidas.

Su forma de implementar las "clases" a partir de funciones constructoras hace que podamos aprovechar muchas técnicas típicas de programación funcional sobre esa clases, proporcionándonos herramientas que no encontramos en otros lenguajes.

Estamos acostumbrados a usar los componentes de ReactJS a través de JSX y es fácil que se nos olvide que, en el fondo, son simples objetos y funciones de Javascript, y podemos usar todas las técnicas habituales para jugar con ellos. Entre ellas, tenemos los componentes de orden superior son una buena forma de encapsular comportamiento de una manera reutilizable y componible.

Posts relacionados:

  1. Un mixin para carga asíncrona de datos en ReactJS
  2. Especificación de tipos en ReactJS con propTypes
  3. Crear un componente con ReactJS

Viewing all articles
Browse latest Browse all 2718

Trending Articles


Girasoles para colorear


mayabang Quotes, Torpe Quotes, tanga Quotes


Tagalog Quotes About Crush – Tagalog Love Quotes


OFW quotes : Pinoy Tagalog Quotes


Long Distance Relationship Tagalog Love Quotes


Tagalog Quotes To Move on and More Love Love Love Quotes


5 Tagalog Relationship Rules


Best Crush Tagalog Quotes And Sayings 2017


Re:Mutton Pies (lleechef)


FORECLOSURE OF REAL ESTATE MORTGAGE


Sapos para colorear


tagalog love Quotes – Tiwala Quotes


Break up Quotes Tagalog Love Quote – Broken Hearted Quotes Tagalog


Patama Quotes : Tagalog Inspirational Quotes


Pamatay na Banat and Mga Patama Love Quotes


Tagalog Long Distance Relationship Love Quotes


BARKADA TAGALOG QUOTES


“BAHAY KUBO HUGOT”


Vimeo 10.7.0 by Vimeo.com, Inc.


Vimeo 10.7.1 by Vimeo.com, Inc.