Tutorial de Introducción a React

JavascriptReact

React es una famosa librería JavaScript de la que se comenzó a escuchar hablar allá por el año 2013. La primera vez que lo utilicé he de decir que me horroricé ante esa mezcla de HTML con JavaScript, que es precisamente lo que había estado tratando de evitar. Sin embargo, lo cierto es que una vez aprendes a dividir tu código frontend en componentes, no hay marcha atrás.

En este tutorial intentaré evitar que os sintáis como yo durante mi fase de aprendizaje de React. Si bien es cierto que en ocasiones repito demasiado las cosas, lo cierto es que intento escribir el tutorial que me gustaría haber tenido cuando aprendí ya no solo React, sino cualquier otra tecnología.

Introducción

Existen ciertos requisitos que deberías tener en cuenta antes de continuar con este tutorial. Si nunca has usado JavaScript o si apenas conoces HTML o CSS, es recomendable que primero aprendas algunos conceptos básicos de estas tecnologías. También deberías saber usar el gestor de paquetes npm. A continuación tienes una serie de tutoriales que podrían servirte de ayuda durante este proceso:

Una vez haya finalizado este tutorial habrás aprendido todos aquellos conceptos básicos de React, como lo que son los componentes, los estados o las propiedades. También aprenderás otros conceptos propios de herramientas que también usaremos, como Webpack, Babel o la sintaxis JSX.

Además, también crearemos una sencilla aplicación de demostración para que puedas aplicar los conceptos aprendidos. A continuación puedes encontrar tanto el código del proyecto que crearemos como un enlace a una versión del mismo en funcionamiento:

Qué es React

React es una librería de JavaScript open source mediante la cual puedes crear vistas utilizando componentes reutilizables. React no es un framework, ya que no te fuerza a crear tu aplicación de uno u otro modo, sino que, al igual que ocurre con jQuery, únicamente te proporciona ciertas herramientas que facilitan la creación de las vistas. Estas herramientas no son en sí componentes o porciones de tu aplicación que ya estén creadas, sino que son un medio para crearlas tú mismo, pudiendo hacerlo de una infinidad de formas distintas.

La versión inicial de React fue creada por facebook en el año 2013, con el objetivo de facilitar la creación de interfaces. Si tenemos en cuenta la arquitectura de creación de aplicaciones MVC (Modelo Vista Controlador), a React le correspondería la capa encargada de la Vista.

El concepto más importante de React es el hecho de poder diseñar tu arquitectura frontend usando compoenentes, que son componentes HTML reutilizables mediante los cuales podrás crear la interfaz de tu aplicación. React también incluye mecanismos de gestión de datos de los componentes, usando propiedades y estados para ello.

Instalación de React

Existen diversos métodos mediante lo cuales puedes instalar y comenzar a utilizar React. A continuación veremos cómo utilizarlo directamente en cualquier proyecto ya existente y también cómo crear una aplicación React con la utilidad Create React APP.

Archivo HTML estático

Para este método vamos a partir de un archivo HTML básico al que vamos a agregar las librerías de React. Sí, el método es más o menos el mismo que usarías para agregar jQuery Este método no es que sea el más utilizado y no es el que seguiremos en este tutorial, pero siempre viene bien saber cómo utilizar React de esta forma.

Si nunca has utilizado herramientas como Node.js o Webpack o si jamás has usado Babel, es recomendable que primero crees un pequeño proyecto de esta forma para no saturarte con tantas herramientas.

Para empezar vamos a crear un archivo llamado index.html. En la cebecera de dicho archivo debemos agregar tres scripts:

  • React: La librería básica de React que contiene la API JavaScript de React que utilizaremos.
  • ReactDOM: Esta librería permite a React interactuar con el DOM mediante la inclusión de métodos específicos para ello.
  • Babel: Se trata de una herramienta que permite transpilar el código de las versiones más modernas de JavaScript a versiones antiguas. El código de las versiones ES6 y ES7 de JavaScript puede que todavía no funcione en todos los navegadores, por lo que es necesario compilar dicho código mediante Babel para transformarlo en su equivalente en versiones de JavaScript que sí son soportadas.

Vamos a incluir estos scripts entre las etiquetas <head> y </head> del archivo index.html. No nos descargaremos los scripts, usando en su lugar una CDN.

También agregaremos un div al que asignaremos el id root, que representará la raíz de nuestra aplicación. El motivo para agregar este último elemento es que en React todos los componentes necesitan tener un elemento padre o raíz, siendo el div root el punto de entrada a la aplicación. Podemos llamarle de cualquier otra forma, pero el uso de root es una convención muy establecida.

Finalmente, también agregaremos un script vació en el body del código HTML, que es donde agregaremos luego nuestro código:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />

    <title>Introducción a React!</title>

    <script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
    <script crossorigin src="https://unpkg.com/browse/babel-standalone@6.26.0/babel.js"></script>
  </head>

  <body>
    <div id="root"></div>

    <script type="text/babel">
      // React code will go here
    </script>
  </body>
</html>

Como ves, hemos usado el atributo crossorigin para agregar los enlaces de la CDN, ya que de esta forma podremos controlar mejor los errores.

Además, si te fijas, también le hemos dado el valor de text/babel al atributo type de nuestro script, que es imprescindible si quieres que Babel funcione con dicho script. De esta forma podremos usar JavaScript ES6 con seguridad.

Ahora vamos a agregar nuestro primer componente de React. A este componente le llamaremos App y lo definiremos mediante una clase usando la sintaxis de ES6:

class App extends React.Component {
  // ...
}

Como ves, los componentes de React extienden la clase React.Component, que dotará a nuestra clase de todas las funciones que implementan los componentes de React.

Los componentes de React que se definen mediante clases no tienen ningún requisito salvo uno, y es que deben contener una implementación para el método render(). Este método se utiliza para renderizar elementos del DOM, por lo que debe devolver código HTML:

class App extends React.Component {
  render() {
    return (
      //...
    );
  }
}

El método render() debe contener la sentencia return y deber devolver código HTML. Por ejemplo, vamos a devolver un encabezado. Lo que verás a continuación te resultará extraño, ya que en teoría debería resultar en un error JavaScript:

class App extends React.Component {
  render() {
    return <h1>Introducción a React</h1>
  }
}

Lo que hemos devuelto son una serie de elementos HTML sin usar comillas. Lo que va después de la sentencia return no es ni código HTML ni JavaScript; se trata de código JSX, que usa una sintaxis muy parecida a la del código HTML. No se producen errores gracias a Babel, que además de transpilar el código JavaScript, también transpilará el código JSX, de forma que pueda ser entendido por tu navegador.

Y finalmente vamos a utilizar el método render() de la librería ReactDOM para renderizar el componente App que hemos crado. Debes especificar también el elemento o nodo del DOM en el que quieres renderizar el componente, que en este caso será el div root:

ReactDOM.render(<App />, document.getElementById('root'));

Antes de ver el resultado de lo que hemos hecho, vamos a ver código completo de nuestro archivo index.html:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />

    <title>Introducción a React!</title>

    <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/babel-standalone@6.26.0/babel.js"></script>
  </head>

  <body>
    <div id="root"></div>

    <script type="text/babel">
      class App extends React.Component {
        render() {
          return <h1>Introducción a React!</h1>
        }
      }

      ReactDOM.render(<App />, document.getElementById('root'));
    </script>
  </body>
</html>

Y tras esto, guarda el archivo index.html y ábrelo con tu navegador para ver el resultado:

Como ves, usar React no es tan complicado como parece. Puedes usar React con cualquier aplicación existente en cuestión de segundos. También puedes ver el código en funcionamiento aquí.

Sin embargo, esto ha estado bien a modo de demostración, pero lo habitual no es usar React de esta forma. El motivo es que el método que hemos usado para cargar las librerías de JavaScript no es el mejor, por no hablar de que renderizar el código y realizar la transpilación con Babel al vuelo no es demasiado eficiente, siendo el resultado difícil de mantener.

Puedes inicializar un proyecto mediante npm y luego instalar estas las librerías de React manualmente, aunque lo más habitual es usar la utilidad Create React App, que es lo que veremos a continuación.

React con Create React APP

Create React App es una aplicación desarrollada por Facebook. No es más que un entorno que incorpora todo lo que necesitarás para crear una aplicación con React. Además de las librerías de React también incorpora un servidor de desarrollo, usando Webpack para compilar automáticamente tanto el código de React como el código CSS, JSX y ES6 o versiones más modernas de JavaScript. Además, también se instalará y configurará ESLint automáticamente con tu proyecto, de modo que puedas seguir un estilo de programación y se muestren avisos cuando compiles y pruebes el código.

Create React App es un excelente modo de comenzar a desarrollar una aplicación con React, independientemente de si se trata de una pequeña aplicación o de una aplicación enorme. Sin embargo, con el tiempo, quizás prefieras crear tu propia configuración de React con Webpack, de modo que puedas instalar todas las dependencias que utilizas con más rapidez.

Para usar Create React App necesitas tener tanto tanto node como el gestor de paquetes npm instalado en tu sistema. Si no tienes estas herramientas instaladas, consulta el tutorial de instalación de Node y npm antes de continuar.

Para crear una aplicación con create-react-app basta con que te desplaces a tu directorio de proyectos; es decir, aquel en el que habitualmente craarías el directorio de un proyecto. Luego ejecuta el siguiente comando para crear un proyecto al que llamaremos tutorial-react:

npx create-react-app tutorial-react

Una vez haya finalizado la instalación del proyecto, desplázate al directorio del proyecto que acabas de crear:

cd tutorial-react

Luego ejecuta el comando npm start para iniciar tanto el servidor de Node como el watch de Webpack, que compilará el código nada más producirse algún cambio en los archivos:

npm start

Se abrirá una nueva ventana con la URL http://localhost:3000/ en la que se mostrará el proyecto de demostración que se instala por defecto con las aplicaciones creadas con Create React App:

A continuación recomiendo que abras el directorio del proyecto con algún IDE como VS Code o Sublime Text, de modo que puedas navegar por los directorios del proyecto con mayor facilidad.

SI observas la estructura de los directorios que se han creado, podrás ver un directorio llamado /public y otro llamado /src. Además también encontrarás el directorio /node_modules creado por Node y los archivos package.json, .gitignore y README.md.

El código compilado que se usará en producción residirá en el directorio /public.html, constando de un único div cuyo id es root. No es necesario importar las librerías aquí. En el directorio /src es en donde estará todo nuestro código React.

Para ver cómo Webpack compila todo el código automáticamente y actualiza el código que reside en el directorio /public, modifica el archivo /src/App.js. Por ejemplo, puedes buscar la siguiente línea de texto y reemplazarla por lo que prefieras:

Edit <code>src/App.js</code> and save to reload.

Si guardas el archivo podrás ver en la terminal un log acerca del compilado del código. Además también podrás ver cómo se refresca lo que ves en el navegador.

Ahora borra todo el contenido del directorio /src a excepción de los archivos index.cssindex.js y App.js, ya que vamos a crear nuestra propia plantilla.

El objetivo de este tutorial no es el de complicarnos la vida con el código CSS, así que nos limitaremos a copiar el código de Bootstrap de aquí y a pegarlo en el archivo index.css. Usaremos Bootstrap de un modo muy básico, aunque si estás interesado, puedes consultar también el tutorial de Boostrap. Si quieres puedes usar cualquier otro framework CSS, como Foundation, Tailwind o cualquier otro que te permita crear un diseño responsivo.

Seguidamente vamos a crear nuestro componente App, por lo que vamos a editar el archivo App.js. Primero debes importar React y luego debes agregar un div con la clase CSS App y, en su interior, vamos a colocar un encabezado con el título del proyecto:

import React from 'react';

class App extends React.Component {
  render() {
    return (
      <div className="App">
        <h1>Tutorial de React de Neoguias!</h1>
      </div>
    );
  }
}
export default App;

Tal y como puedes ver, hemos usado la función render() con la sentencia return, que incluye el código JSX que mostrará por pantalla. Supongo que te llamará la atención que usemos el atributo className para definir la clase en lugar del atributo class. Esto es debido a que no estamos usando código HTML, sino código JSX, que usa el atributo className para definir las clases, ya que class es una palabra reservada de JavaScript.

Guarda el archivo App.js y luego edita el archivo index.js, en donde debes importar tanto React como ReactDOM, además de importar también el archivo index.css. Y finalmente vamos a renderizar el componente App en el elemento root del archivo index.js:

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';

ReactDOM.render(
  <App />,
  document.getElementById('root')
);

Si ahora revisas de nuevo la URL http://localhost:3000/, verás que ahora se muestra el encabezado "Tutorial de React de Neoguias!".

Enhorabuena, porque ya has creado tu primero componente con React.

Dev Tools de React

Antes de continuar vamos a hacer un pequeño interludio. Existe una extensión para chrome llamada React DevTools que resulta muy útil cuando trabajas con React. Puedes descargar la extensión para diferentes navegadores desde los siguientes enlaces:

Una vez hayas instalado la extensión, podrás ver una nueva pestaña llamada Componentes cuando abras las herramientas para desarrollador de tu navegador. En dicha pestaña podrás ver una lista con los componentes de React. Podrás inspeccionar tanto las propiedades como el estado de cada componente. También verás otra pestaña llamada Profiler mediante la cual podrás analizar los posibles problemas de rendimiento de tu aplicación.

Y con esta herramienta instalada ya tendrás todo lo que necesitas para trabajar con React.

Introducción a JSX

Tal y como has visto, hasta ahora no hemos usado HTML en nuestro código React, sino que hemos usado ese bicho raro llamado JSX. El nombre de JSX viene de la combinación de las palabras JavaScript y XML. Mediante JSX podemos crear código HTML con una sintaxis algo distinta, pudiendo además usar nuestras propias etiquetas XML. Dicho de otro modo, JSX permite usar código XML en JavaScript.

No solamente podrás usar JSX en el método render() de tus componentes, sino que lo podrás en cualquier parte de tu código JavaScript. A continuación vamos a asignar un encabezado escrito mediante la sintaxis JSX a una variable:

const encabezado = <h1 className="titulo">Hola, colega!</h1>;

Sin embargo, el uso de JSX en React es totalmente opcional. De hecho existen muchos otros lenguajes que podrías usar en lugar de JSX. Si lo prefieres también puedes hacer exactamente lo mismo con código JavaScript puro, para lo cual puedes usar el método React.createElement().

A continuación vamos a reescribir la asignación anterior sin usar JSX. Para ello usaremos el método React.createElement(), que acepta el nombre de la etiqueta como primer parámetros, un objeto con los atributos de la etiqueta como segundo parámetro y los elementos o componentes que estarán en el interior del componente como tercer parámetro:

const encabezado = React.createElement(
  'h1',
  { className: 'titulo' },
  'Hola, colega!'
);

Aunque puedan parecer similares, JSX dista mucho de ser HTML. A continuación tienes una lista con las diferencias más destacables que existen entre HTML y JSX:

  • En lugar de usar class para agregar las clases CSS; debes usar className, ya que class es una palabra reservada.
  • Siempre que cierres la etiqueta que carece de etiqueta de cierre debes usar una barra inclinada, tal que así <img/>.
  • Debes escribir las propiedades y los métodos con notación Camel Case. Es decir, comenzando por letra minúscula y, seguidamente, cada nueva palabra comenzará por mayúscula.

Quizás te estés preguntando qué debes hacer en caso de que quieras usar código JavaScript en JSX. Para ello basta con escribir las expresiones JavaScript, ya sean constantes, variables, funciones o propieades entre dos llaves:

const nombre = 'Colega';
const encabezado = <h1 className="titulo">Hola, {nombre}!</h1>

Desde luego, el uso de JSX te ahorrará muchísimo tiempo en comparación de si usases JavaScript para crear y agregar los componentes.

Crea Componentes

En React puedes crear dos tipos de componentes, que son los componentes de clase y los compontes funcionales. Por ahora hemos creado el componente App, que es el que suele usar como principal en las aplicaciones que usan React. Para crear este componente hemos usado una clase, por lo que estamos ante un componente de clase.

Las aplicaciones de React están formadas por múltiples pequeños componentes que agregamos como descendientes de componente App. Lo habitual es que cada uno de estos componentes esté definido en el interior de su propio archivo JavaScript, tal y como hemos con el componente App.

Cuando creas un componente, debes exportarlo tal y como hemos hecho en la sentencia export default App. Luego debes importarlo en el archivo en el que quieras renderizarlo. Si quieres puedes definir varios componentes en un mismo archivo, pero en cuanto la aplicación crezca comenzará a ser muy difícil de gestionar.

Componentes de Clase

Para explicar en detalle este tipo de componentes vamos a crear un componente adicional. Vamos a crear el componente Tabla en el archivo Tabla.js. Usaremos una clase que por convención comenzará por letra mayúscula, diferenciándose así de los componentes HTML que se incluyen por defecto con React. En la tabla agregaremos un simple listado de personas. Aquí tienes el código completo de la clase:

import React, { Component } from 'react';

class Tabla extends Component {
  render() {
    return (
      <table className="table">
        <thead>
          <tr>
            <th>Nombre</th>
            <th>Apellido</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td>Clark</td>
            <td>Kent</td>
          </tr>
          <tr>
            <td>Bruce</td>
            <td>Wayne</td>
          </tr>
          <tr>
            <td>Peter</td>
            <td>Parker</td>
          </tr>
          <tr>
            <td>Selina</td>
            <td>Kyle</td>
          </tr>
        </tbody>
      </table>
    );
  }
}

export default Tabla;

Seguidamente vamos a agregar el componente Tabla en nuestro archivo App.js, aunque primero debemos importarlo:

import Tabla from './Tabla';

Ahora ya podemos renderizar el componente en el interior del método render() del componente App. Para ello vamos a agregar un div y en su interior vamos a agregar la etiqueta correspondiente de nuestro componente:

import React, { Component } from 'react';
import Tabla from './Tabla';

class App extends Component {
  render() {
    return (
      <div className="container">
        <h1>Tutorial de React de Neoguias!</h1>
        <Tabla />
      </div>
    )
  }
}

export default App;

Es importante destacar que todo componente de React debe tener un único elemento como raíz. De obviar el container y situar el encabezado y la tabla en la sentencia return, obtendríamos un error

Si ahora observas de nuevo el resultado en el navegador, deberías ver lo siguiente:

La mejor parte de React es que podrás reutilizar este componente en cualquier otra parte, e incluso usar varias instancias simultáneamente en una misma página. Sin embargo, todavía se trata de un componente estático. No te preocupes, ya que dentro de nada veremos cómo hacer que esta tabla sea dinámica.

Componentes Funcionales

Lo habitual es ver primero los componentes funcionales y luego los otros, aunque lo cierto es que cuando aprendí React hubiese preferido que fuese al revés, y este es el motivo de que los hayamos dejado para el final. Estos componentes son simples funciones que no se definen mediante una clase.

A modo de ejemplo, lo que vamos a hacer ahora es dividir nuestro componente Tabla en dos componentes; uno representará la cabecera de la tabla y otro el cuerpo. Vamos a usar funciones flecha ES6. En caso de que no sepas en qué se diferencian de las normales, consulta el siguiente tutorial, en el que explico brevemente en qué se diferencian las funciones flecha de las normales.

Primero definiremos un componente para la cabecera de la tabla, cuyo código situaremos en un nuevo archivo llamado /HeadTabla.js:

import React from 'react';

const HeadTabla = () => {
  return (
    <thead>
      <tr>
        <th>Nombre</th>
        <th>Apellido</th>
      </tr>
    </thead>
  );
}
  
export default HeadTabla;

Ahora vamos a de definir otro componente para el cuerpo de la tabla, cuyo código situaremos en un nuevo archivo llamado /BodyTabla.js:

import React from 'react';

const BodyTabla = () => {
  return (
    <tbody>
      <tr>
        <td>Clark</td>
        <td>Kent</td>
      </tr>
      <tr>
        <td>Bruce</td>
        <td>Wayne</td>
      </tr>
      <tr>
        <td>Peter</td>
        <td>Parker</td>
      </tr>
      <tr>
        <td>Selina</td>
        <td>Kyle</td>
      </tr>
    </tbody>
  );
}

export default BodyTabla;

A continuación debemos importar el archivo los componentes HeadTabla y BodyTabla en nuestro componente Tabla, que tendremos que reescribir tal que así:

import React, { Component } from 'react';
import HeadTabla from './HeadTabla';
import BodyTabla from './BodyTabla';

class Tabla extends Component {
  render() {
    return (
      <table className="table">
        <HeadTabla/>
        <BodyTabla/>
      </table>
    );
  }
}

export default Tabla;

Tal y como puedes ver, hemos incluido ambos componentes en el interior del componente Tabla.

Ya puedes observar de nuevo el navegador para ver el resultado, que debería ser el mismo que el anterior.

Gestiona Componentes

Ya hemos visto cómo crear componentes. Lo que debes tener siempre en cuenta, ya uses una función o una clase para declarar un componente, es que la la sentencia return de los componentes funcionales y la sentencia return del método render de los componentes declarados con una clase, debe contener un único elemento como padre del resto.

Dicho esto, vamos a ver los dos elementos esenciales de los componentes de React, que son su estado y sus propiedades.

Propiedades de un componente

Por ahora tenemos una tabla con unos datos fijos que no es dinámica. Sin embargo, uno de los mejores apartados de React es el modo mediante el cual gestiona los datos de los componentes mediante su estado y sus propiedades. Por ahora nos vamos a centrar en las propiedades y, como primer paso, vamos a eliminar todas las filas del componente BodyTabla:

import React from 'react';

const BodyTabla = () => {
  return (
    <tbody>
    </tbody>
  );
}
  
export default BodyTabla;

A continuación vamos a crear un array de objetos en el método render() del componente App, simulando una llamada a una API que por ahora todavía no vamos a crear. Para ello, edita el archivo App.js y agrega el siguiente array en el método render():

import React from 'react';
import Tabla from './Tabla';

class App extends React.Component {
  render() {

    const personas = [
      {
        nombre: 'Clark',
        apellido: 'Kent',
      },
      {
        nombre: 'Bruce',
        apellido: 'Wayne',
      },
      {
        nombre: 'Peter',
        apellido: 'Parker',
      },
      {
        nombre: 'Selina',
        apellido: 'Kyle',
      },
    ];  

    return (
      <div className="container">
        <h1>Tutorial de React de Neoguias!</h1>
        <Tabla />
      </div>
    );
  }
}
export default App;

A continuación vamos a pasarle la lista de personas al componente Tabla. Para ello tendremos que pasarle la lista como una propiedad, cuya sintaxis sería la misma que la de un atributo HTML:

return (
  <div className="container">
    <h1>Tutorial de React de Neoguias!</h1> 
    <Tabla datosPersonas={personas} />
  </div>
);

Hemos usado el nombre datosPersonas para la propiedad, pero podríamos haber utilizado cualquier otro nombre para la misma a excepción de una palabra reservada. Dado que pasamos el valor usando la constante persona, es importante utilizar una llave de apertura y otra de cierre a ambos lados de la misma, ya que tal y como hemos explicado antes, es el modo de poder incluir expresiones JavaScript en JSX.

Ahora vamos a ver cómo obtener la propiedad datosPersonas desde el componente Tabla. En los componentes de React, podrás acceder a cualquier propiedad desde el la propiedad this.props:

class Tabla extends Component {
  render() {
    const { datosPersonas } = this.props;

    return (
      <table className="table">
        <HeadTabla/>
        <BodyTabla/>
      </table>
    );
  }
}

Lo que hemos hecho es obtener el valor de la propiedad datosPersonas que le hemos pasado al componente Tabla mediante destructuring del objeto this.props, presente en todos los componentes de React.

Si abres las DevTools de React desde tu navegador y accedes a la sección Components, podrás ver que el array con los datos de las personas está declarado en la sección props. Todos estos datos se almacenan en una versión virtual de DOM, que es un método bastante eficiente que se utiliza para sincronizar los datos de los componentes con el DOM real. No solo React usa un DOM virtual, sino que otras librerías como Vue también lo utilizan.

Podemos acceder en cualquier momento a las propiedades de un componente mediante la sintaxis this.props.propiedad, reemplazando propiedad por el nombre de la propiedad en cuestión. Sin embargo, tal y como hemos visto en nuestro ejemplo, también podemos usar la sintaxis de destructuring de objetos de ES6 tal que así const { prop1, prop2, ..., propn } = this.props, requiriendo menos líneas de código cuando tenemos más de una propiedad.

Además, dado que nuestro componente Tabla usa varios componentes para representar los datos, vamos a pasar la lista de persona al componente BodyTabla mediante otra propiedad con el mismo nombre:

class Tabla extends Component {
  render() {
    const { datosPersonas } = this.props;
    
    return (
      <table className="table">
        <HeadTabla/>
        <BodyTabla datosPersonas={datosPersonas} />
      </table>
    );
  }
}

Ahora vamos a editar el componente BodyTabla. Cuando usamos componentes funcionales, debemos pasarles las propiedades como primer parámetro de la función.

Lo que vamos a hacer es usar el método map() de los arrays de JavaScript para recorrer los elementos de la propiedad datosPersonas y representar los datos como una serie de filas y columnas del cuerpo de la tabla. Almacenaremos el resultado de la operación en la constante filas, que luego asignaremos al cuerpo de la tabla:

const BodyTabla = (props) => {
  const filas = props.datosPersonas.map((fila, indice) => {
    return (
      <tr key={indice}>
        <td>{fila.nombre}</td>
        <td>{fila.apellido}</td>
      </tr>
    );
  })

  return <tbody>{filas}</tbody>
}

Si ahora echas un ojo de nuevo al resultado en el navegador, podrás ver que la tabla está representada con todos los datos de nuevo:

Tal y como has podido ver, hemos usado el atributo key para los elemento de la tabla. Aunque el código funcionará si no agregas claves a las listas de elementos de JSX, es más que recomendable agregarlas, ya que así podrás identificar cada uno de los elementos de la tabla. Además, más adelante veremos cómo en efecto son útiles cuando queremos modificar la tabla.

Las propiedades son útiles cuando creamos el componente o queremos asignarle datos existentes, pero un componente en sí mismo no puede modificar sus propiedades, ya que son de solo lectura. Es aquí cuando entra en juego el estado de un componente, que es quizás el segundo elemento más importante de React. Sí, podrías modificar el DOM directamente, pero entonces necesitarías un montón de líneas de código para hacer lo que vamos a hacer a continuación.

Estado de un componente

Por lo de pronto hemos utilizado un array para almacenar los datos de nuestra tabla, que hemos ido pasando por los diferentes componentes hasta renderizar estos datos en el cuerpo de la tabla. Sin embargo, si quisiéramos modificar la tabla, ya sea agregando o eliminado datos de la misma, mediante las propiedades tendríamos un único camino, ya que estas son inmutables.

Es por ello que existe el estado, que nos permite actualizar los datos del componente y refrescar automáticamente el mismo cuando este se altera. El estado de un componente es algo así como un almacén de datos dinámico del cual podemos agregar o eliminar elementos, además de poder modificarlos. Para empezar, vamos a crear el objeto state dentro del componente App:

class App extends Component {
  state = {}
}

Es importante que el objeto que almacena el estado de un componente tenga el nombre state, que es el que React espera que tenga. En el interior de este objeto estarán todas y cada una de las variables de estado. En nuestro caso, vamos a mover el array de personas que habíamos agregado en el método render de la clase App al estado de dicha clase:

class App extends Component {
  state = {
    personas: [
      {
        nombre: 'Clark',
        apellido: 'Kent',
      },
      {
        nombre: 'Bruce',
        apellido: 'Wayne',
      },
      {
        nombre: 'Peter',
        apellido: 'Parker',
      },
      {
        nombre: 'Selina',
        apellido: 'Kyle',
      },
    ],
  }
}

Ahora nuestro array de personas está ya definido como parte del estado del componente App.

Vamos agregar una funcionalidad que nos permita agregar o eliminar personas del estado. Para ello vamos a agregar un método llamado eliminarPersona() en la clase App:

eliminarPersona = (indice) => {
  const { personas } = this.state

  this.setState({
    personas: personas.filter((personas, i) => {
      return i !== indice;
    }),
  });
}

Tal y como puedes ver, hemos usado el método setState() en el interior del método eliminarPersona(). Siempre que quieras modificar el estado de un componente en React debes usar el método setState(), que se incluye por defecto en los componente con el objetivo de manipular el estado. De este modo, React podrá plasmar el resultado de los cambios en el DOM. De hecho, si modificas el estado mediante una asignación directa, verás que nuestro ejemplo no funciona.

Para eliminar el elemento indicado del array hemos usado el método Array.filter(), filtrando el array en base al elemento indicando en el indice, que será el único que no vamos a incluir en el nuevo array resultante del proceso de filtrado. El método Array.filter() acepta una función como parámetro que se aplicará a todos y cada uno de los elementos del array.

Lo que vamos a hacer ahora es pasar la función como una propiedad del componente Tabla para así mostrar un botón al final de cada fila de la tabla que nos permita eliminar a cualquier persona:

render() {
  const { personas } = this.state;

  return (
    <div className="container">
      <h1>Tutorial de React de Neoguias!</h1>
      <Tabla datosPersonas={personas} eliminarPersona={this.eliminarPersona} />
    </div>
  )
}

Del mismo que hemos pasado la función al componente Tabla, también debemos pasársela al componente BodyTabla como una propiedad desde el componente Tabla.

import React, { Component } from 'react';
import HeadTabla from './HeadTabla';
import BodyTabla from './BodyTabla';

class Tabla extends Component {
  render() {

    const { datosPersonas, eliminarPersona } = this.props;

    return (
      <table className="table">
        <HeadTabla/>
        <BodyTabla datosPersonas={datosPersonas} eliminarPersona={eliminarPersona} />
      </table>
    )
  }
}

export default Tabla;

Ahora vamos a modificar el componente BodyTabla, siendo ahora cuando tendremos que agregar un botón en cada fila de la tabla que permita eliminar dichas filas. Para ello usaremos la clave o key que hemos agregado en cada una de las filas. De esta forma, la función de filtrado sabrá cuál es la fila que debe eliminar. Vamos a crear una columna adicional con dicho botón:

import React from 'react';

const BodyTabla = (props) => {
    const filas = props.datosPersonas.map((fila, indice) => {
      return (
        <tr key={indice}>
          <td>{fila.nombre}</td>
          <td>{fila.apellido}</td>
          <td>
            <button onClick={() => props.eliminarPersona(index)}>Eliminar</button>
          </td>
        </tr>
      )
    })

    return <tbody>{filas}</tbody>
}
export default BodyTabla;

Ahora observa de nuevo el proyecto en tu navegador y prueba a eliminar alguna persona:

En este caso hemos eliminado a Clark Kent.

Gestión de formularios

Tenemos una tabla en la que se almacenan datos de varias personas que podemos eliminar, lo cual es totalmente inútil si no podemos agregar nuevas filas. Para ello necesitas agregar nuevos datos al estado del componente App. De hecho no estaría mal si comenzamos con un estado vacío y partiendo de ahí vamos agregando nuevos elementos. Así que para empezar vamos a eliminar los datos que asignamos inicialmente al array state.personas de la clase App:

class App extends Component {
  state = {
    personas: [],
  }
}

A continuación vamos a crear un nuevo componente en un archivo nuevo. Este componente será un formulario al que daremos el nombre de Form y que nos permitirá agregar una nueva fila al formulario, para lo cual necesitamos un campo nombre y otro campo apellido. Además, vamos a asignar un estado inicial a los datos de dicho componente:

import React, { Component } from 'react';

class Form extends Component {
  state = {
    nombre: '',
    apellido: '',
  };
}

Lo que vamos a hacer es actualizar el estado del componente Form cada vez que el usuario modifique algún campo y, cuando se envíe el formulario, pasaremos los datos al estado del componente App, actualizando el componente Tabla.

Vamos a crear una función que se ejecute cada vez que modifiquemos un campo del formulario, a la que únicamente le pasaremos el evento del usuario como parámetro. Con estos datos, vamos a modificar los elemento nombre y apellido del estado del formulario. Vamos a utilizar una sola función que sirva para modificar cualquier campo del formulario:

gestionarCambio= (event) => {
  const { campo, valor } = event.target;

  this.setState({
    [campo]: valor,
  });
}

A continuación vamos a agregar el método render() del formulario, a cuyos campos nombre y apellido les asignaremos como valor el correspondiente valor de las variables de estado:

render() {
  const { nombre, apellido } = this.state;

  return (
    <form>
      <label htmlFor="nombre">Nombre</label>
      <input
        type="text"
        name="nombre"
        id="nombre"
        value={nombre}
        onChange={this.gestionarCambio} />
      <label htmlFor="apellido">Apellido</label>
      <input
        type="text"
        name="apellido"
        id="apellido"
        value={apellido}
        onChange={this.gestionarCambio} />
    </form>
  );
}

export default Form;

Tal y como ves, hemos asignado la función gestionarCambio() al evento onChange de ambos campos. Finalmente vamos a exportar el componete:

export default Form;

Aquí tienes el código completo del componente Form:

import React, { Component } from 'react';

class Form extends Component {
  state = {
    nombre: '',
    apellido: '',
  };

  gestionarCambio= (event) => {
    const { name, value} = event.target;
      
    this.setState({
      [name]: value,
    });
  }

  render() {
    const { nombre, apellido } = this.state;
      
    return (
      <form>
        <div className="form-group">
          <label htmlFor="nombre">Nombre</label>
          <input type="text" name="nombre" id="nombre" className="form-control" value={nombre} onChange={this.gestionarCambio} />
        </div>
        <div className="form-group">
          <label htmlFor="apellido">Apellido</label>
          <input type="text" name="apellido" id="apellido" className="form-control" value={apellido} onChange={this.gestionarCambio} />
        </div>
      </form>
    );
  } 
}
      
export default Form;

Ahora vamos a importar el componente Form en el archivo App.js:

import Form from './Form';

Y seguidamente vamos a renderizarlo debajo de nuestra tabla:

return (
  <div className="container">
    <h1>Tutorial de React de Neoguias!</h1>
    <Tabla datosPersonas={personas} eliminarPersona={this.eliminarPersona} />
    <Form />
  </div>
);

Si ahora observas el navegador, verás que ahora se muestran los campos del formulario, que modifican el estado del mismo cuando cambias su valor. Sin embargo, todavía tenemos que crear una función que envíe los datos del formulario y actualice la variable de estado personas del componente App, agregando una nueva persona a la tabla.

Edita el archivo App.js y agrega la siguiente función al componente:

enviarFormulario = (persona) => {
  this.setState({ personas: [...this.state.personas, persona] });
}

Lo que hemos hecho es modificar el contenido de la variable de estado this.state.personas, asignándole los valores que ya estaban presentes mediante el operador spread ... más una nueva persona.

Ahora en el propio componente App, vamos a pasar el método enviarFormulario() como una propiedad al componente Form, de modo que sepa lo que ha de hacer cuando enviemos el formulario:

<Form enviarFormulario={this.enviarFormulario} />

Ahora tenemos que agregar un campo input al formulario con un evento onClick, de modo que se procese el envío del formulario. Podríamos llamar directamente al método enviarFormulario() que pasamos al formulario, pero lo ideal sería que los campos se reseteasen al enviarlo, por lo que vamos a agregar el siguiente método en el componente Form:

enviarFormulario = () => {
  this.props.enviarFormulario(this.state);
  this.setState({
    nombre: '',
    apellido: '',
  });
}

Y finalmente tenemos que agregar el botón de envío al formulario:

<input type="button" value="Enviar" onClick={this.enviarFormulario} />

Ahora ya podrás acceder de nuevo a tu navegador y agregar o eliminar todos los usuarios que quieras.

Comprendo que llegados a este punto quizás puedas estar pensando que React es complicado. El tema es dejar de pensar en página web y pensar más bien como si estuvieses creando una aplicación que funciona por ciclos; como si se tratase de un juego cuyos componentes se actualizan con cada ciclo.

En caso de que te hayas perdido en algún paso, consulta el código del proyecto en GitHub

Build & Deploy de la aplicación React

Todo lo que has hecho hasta ahora ha sido en tu entorno de desarrollo. El compilado de la aplicación se ha realizado al vuelo. Sin embargo, cuando usas la aplicación en producción es deseable tener una serie de archivos estáticos con los scripts ya compilados y minimizados. Además también querremos subir nuestro proyecto a nuestro servidor o al lugar en el que queramos que resida. A primero proceso se le llama build y al segundo despliegue o deploy.

La compilación de todos los recursos de React es muy sencilla, ya que bastará con que ejecutes el siguiente comando:

npm run build

Una vez finalizado el proceso verás que se muestra un mensaje de confirmación y que además se ha creado un nuevo directorio llamado build que contiene tu aplicación compilada, pudiendo subir directamente los archivos al mismo al lugar en el que quieras que residan.

Sin embargo, vamos a probar también a subir el proyecto a un servidor remoto, usando concretamente el servicio de GitHub Pages, ideal para subir proyectos de prueba. Es por ello que si nunca has usado Git, es recomendable que consultes el tutorial de introducción a Git antes de continuar. Debes asegurarte de que has creado un repositorio para tu proyecto en GitHub.

Para cumplir nuestro cometido es recomendable que cierres el proceso de React desde la terminal, pulsando CTRL+C en Linux y Windows o CMD+C en Mac. A continuación edita el archivo package.json, en el que vamos a agregar la página de GitHub Pages en la que estará nuestro proyecto:

"homepage": "https://neoguias.github.io/tutorial-react",

Asegúrate de que la URL que introduces usa tu nombre de usuario en lugar de neoguias. También agregaremos los siguientes scripts, requeridos por GitHub Pages, además de los ya existentes:

"scripts": {
  // ...
  "predeploy": "npm run build",
  "deploy": "gh-pages -d build"
}

A continuación guarda el archivo package.json e instala también el paquete de Node gh-pages mediante el siguiente comando:

npm install --save-dev gh-pages

Ahora, dado que hemos hecho cambios, vamos a hacer de nuevo el build de nuestra aplicación:

npm run build

Y finalmente vamos a desplegar la aplicación en la URL indicada mediante el siguiente comando:

npm run deploy

Espera a que finalice el proceso y luego accede a la URL que has indicado, en donde podrás ver tu proyecto en funcionamiento.

En mi caso, el proyecto está ahora disponible en https://neoguias.github.io/tutorial-react

Finalizando

En este tutorial has aprendido los conceptos básicos de React y realmente es lo que lo usarás la mayor parte de las veces. Hemos visto lo que son las propiedades de un componente y su estado, además de haber gestionado interacciones entre los componentes. Finalmente también hemos puesto en marcha en proyecto.

Sin embargo, este ha sido solo el punto de partida, ya que existen muchas más cosas que puedes aprender. Algo muy común es por ejemplo el uso de React con Redux, que en cuanto practiques algo más con React podría ser tu siguiente paso.


Avatar de Edu Lazaro

Edu Lázaro: Ingeniero técnico en informática, actualmente trabajo como desarrollador web y programador de videojuegos.

👋 Hola! Soy Edu, me encanta crear cosas y he redactado esta guía. Si te ha resultado útil, el mayor favor que me podrías hacer es el de compatirla en Twitter 😊

Si quieres conocer mis proyectos, sígueme en Twitter.

3 comentarios en “Tutorial de Introducción a React

Deja una respuesta

“- Hey, Doc. No tenemos suficiente carretera para ir a 140/h km. - ¿Carretera? A donde vamos, no necesitaremos carreteras.”