Crear un componente con ReactJS

En el anterior post explicaba cuál es el enfoque de ReactJS para construir interfaces de usuario. Después de sentar las bases de la filosofía que hay detrás de ReactJS, en este post vamos a ver un pequeño ejemplo que nos permita hacernos una idea más clara que cómo se utiliza ReactJS.

El componente de ejemplo

El componente de ejemplo que vamos a construir está formado por una lista cervezas en la que podemos ir incrementando la cantidad de cervezas ingeridas y nos mostrará el total consumido hasta el momento. El aspecto será algo así:

react-sample

Lo primero que necesitamos es decidir de qué forma vamos a organizar la información que vamos a mostrar, decidiendo qué componentes vamos a crear y qué información será inmutable (propiedades) en cada componente y qué información será mutable (estado) en cada componente.

En este caso, podemos tener un componente que llamaremos BeerItem que represente cada elemento de lista. Este componente recibirá como propiedades inmutables el nombre de la cerveza a mostrar, el número de veces que se ha consumido, y la función callback que se invocará al tomarnos una cerveza más.

Además, tendremos un componente, BeerList que encapsula la lista de cervezas y la cuenta total. Esta información es mutable para este componente y, por tanto, formará parte de su estado. Cada vez que se incremente la cuenta de una cerveza, se modificará el estado de este componente y, por tanto, se provocará un nuevo renderizado del componente actualizando el DOM generado.

Creado los componentes

Un componente en ReactJS es un objeto javascript que contiene una serie de funciones y propiedades que son gestionadas por ReactJS. Para crear un componente, se debe utilizar la función React.createClass. Nuestro componente para mostrar un elemento de lista es el siguiente:

var BeerItem = React.createClass({
  incCount: function() {
    this.props.addOne(this.props.beer);
  },
  render: function() {
    return <li>[{this.props.count}] {this.props.beer} <button onClick={this.incCount}>Una más</button></li>;
  }
});

En el objeto que pasamos a createClass estamos definiendo la función render que se encarga de generar el DOM asociado al componente y una función adicional incCount que usa el componente para gestionar el evento asociado al click del botón.

Para acceder a las propiedades inmutables recibidas por el componente debemos usar this.props. Estas propiedades las recibe el componente en el momento de crearlo, cosa que haríamos con un código similar a éste:

<BeerItem beer="Mahou 5 estrellas" count=4 addOne=someFuncToAddOneBeer />

Lo más llamativo de todo esto es esa especie de pseudohtml que aparece mezclado con el código de javascript y que se usa como valor de retorno de la función render. Este pseudohtml es lo que ReactJS llama JSX, Javascript XML y ayuda a definir el DOM de una forma más cómoda. ReactJS cuenta con herramientas para convertir esta sintaxis a funciones Javascript “puras”, y aunque podemos hacer eso manualmente, en general resulta más claro usar JSX para definir los componentes.

La transformación se puede realizar directamente en el browser o en un proceso de precompilación en el servidor, lo que permite ahorrar tiempo de ejecución en el cliente y reutilizar las plantillas ya compiladas.

Ahora que tenemos el componente para mostrar una cerveza, vamos cómo es el componente que muestra la lista completa:

var BeerList = React.createClass({
  getInitialState : function() {
    return {
      beers: [
        {name: "Mahou 5 estrellas", count: 0},
        {name: "Cibeles Imperial IPA", count: 0},
        {name: "Chimay Triple", count: 0}
      ]
    };
  },

  addOne : function(beerName) {
    var beers = this.state.beers,
      beer = beers.filter(function(x) { 
        return x.name === beerName;
      })[0];

    beer.count ++;

    this.setState({beers: beers});
  },

  render: function() {
    var total, beerItems;

    total = this.state.beers.reduce(function(acc, x) {
      return acc + x.count;
    }, 0);

    beerItems = this.state.beers.map(function(x) {
      return <BeerItem beer={x.name} count={x.count} addOne={this.addOne} />;
    }, this);

    return <div><p>Llevas {total} cervezas</p><ul>{beerItems}</ul></div>;
  }
});

Este componente mantiene estado mutable, por lo que aparece la función getInitialState, que devuelve el estado inicial, y se utiliza la función setState para actualizar el estado. Cada vez que se invoca la función setState ReactJS se encarga de volver a llamar a la función render para volver a generar el DOM.

En su función render se están creando componentes de tipo BeerItem como los que hemos definido antes para representar cada elemento de la lista, y estamos asignándoles sus propiedades (información inmutable) a través de atributos del JSX. Como se puede ver, la forma de “comunicar” los componentes hijos con el componente padre es a través de una función callback, addOne, que se pasa como una propiedad más del hijo.

Si os fijáis, cada vez que se incrementa la cuenta de una cerveza se actualiza el estado, lo que fuerza a regenerar el DOM de todas las cervezas. Recordad que en realidad ReactJS trabaja generando un DOM virtual que luego compara con el DOM real para lanzar los mínimos cambios necesarios, por lo que esto no supone un problema de rendimiento. A cambio, cuando estamos en el método render tenemos toda la información (estado y propiedades) disponible, por lo que es muy sencillo razonar sobre ella y tomar las decisiones de renderizado adecuadas.

Por último, para empezar a mostrar un componente de ReactJS en una página debemos usar la función React.renderComponent indicando el componente a mostrar y el elemento HTML en el que vamos a insertar el DOM generado por el componente:

React.renderComponent(, document.getElementById('content'));

Podéis jugar con el código completo del ejemplo en este fiddle.

Resumen

Crear componentes de ReactJS es bastante sencillo, aunque hay que tener claro qué tipo de información queremos que sea mutable e inmutable en cada componente y cual es la jerarquía de componentes que queremos montar. Esto puede resultar algo confuso al principio, especialmente si estás acostumbrado al uso de patrón MVVM donde toda la información es mutable y la comunicación entre componentes se puede realizar en cualquier dirección y no sólo de padres a hijos.

Aunque no sea obligatorio, usar JSX es muy recomendable para generar el DOM porque mejora mucho la legibilidad. Lo malo es que eso hace necesario recurrir a herramientas externas para convertir el JSX a javascript puro, y eso complica un poco la experiencia de desarrollo. Aun así, en el próximo post veremos como podemos preparar un flujo de trabajo que nos simplifique la vida.


Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos necesarios están marcados *

*

Puedes usar las siguientes etiquetas y atributos HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>