Entendiendo React desde el CDN

El desarrollo web a cambiado bastante desde sus inicios. Hace algunos años solo se usaba HTML, CSS y un poco de JavaScript para crear páginas web. Hoy en día las páginas web son aplicaciones complejas con la misma capacidad que las aplicaciones de escritorio. Sin embargo, para lograr esto no basta estas tecnologías, se necesita de herramientas que nos permitan crear interactividad en nuestra web y demás capacidades que se necesitan en una aplicación web. De eso se encargan los frameworks y librerías como React.

En este tutorial aprenderemos qué es React y como funciona dentro de un archivo HTML, además entenderemos la importancia de JSX para crear aplicaciones web con un código de sintaxis fácil y segura.

Índice

  1. Qué es React
  2. Nuestro primer elemento
  3. Anidando elementos
  4. Los Props como parámetros de un componente
  5. Por qué JSX
  6. El primer Hook useState

1. Qué es React

Lo primero que debemos tener en cuenta es que React no es un Framework para hacer SPAs (Single Page Applications) si no más bien una librería para construir interfaces de usuario web. A diferencia de un framework que te proporciona todo un marco de trabajo como Angular que al crear un proyecto ya tenemos muchas herramientas instaladas para diversas funciones y características de nuestro proyecto. En React comenzamos con lo básico y nosotros debemos ir agregando las herramientas según las necesitemos.

React tiene tres características importantes que debemos conocer y que se resaltan en la documentación oficial. El primero es que React es declarativo, o sea forma parte del paradigma de la programación declarativa. Esto nos quiere decir que en React no tenemos el control del flujo, ya que utilizamos funciones, métodos y patrones establecidos por React que no son completamente transparentes para el desarrollador. Por ejemplo, React internamente toma decisiones que le permitirá volver a renderizar un componente con el cambio mínimo posible, y nosotros no tenemos control sobre las decisiones que toma React para lograr esto. Esto es muy distinto a programar usando solo JavaScript y HTML donde nosotros hacemos uso de una programación imperativa, indicándole al código que hacer a cada momento, por ejemplo, cuándo volver a renderizarse, cuándo mostrar algo o qué hacer cuando suceda algún evento. Mientras que con React, este es el que se encarga de controlar todo ese flujo de decisiones.

La segunda característica importante de React es que programar con React es programar basado en componentes. Los componentes nos permitirán encapsular la lógica Javascript y la estructura HTML y CSS usando funciones o clases de tal manera que podamos usarlas en cualquier parte de nuestra aplicación, como si de piezas de lego se tratasen.

La tercera y última característica que vemos en la página principal de la documentación de React es Learn once, Write Anywhere (Aprende una vez, escribe donde sea) lo que nos dice que React puede ser usado en distintas plataformas ya que podemos usar React en el servidor usando Nodejs, en el frontend que será lo que aprenderemos en este tutorial y hasta en dispositivos móviles usando React Native.

2. Nuestro primer elemento

La forma más simple pero no tan popular de usar React es usando el CDN de React. Para esto, dentro del código HTML, necesitamos agregar el CDN de react.development.js que contiene el core de React y es necesario para cualquier dependencia derivada de React. Y además debemos agregar el CDN de react-dom.development.js en nuestro proyecto, para realizar operaciones en el DOM como agregar elementos. Veamos el siguiente código que lo puedes usar como template.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Hello World</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>
  </head>
  <body>
    <div id="app">
      <!-- Contenedor para los elementos de React -->
    </div>
    <script>
      // Código js
    </script>
  </body>
</html>

Ahora crearemos nuestro primer elemento para el DOM utilizando React. Así que seguiremos los siguientes pasos para lograrlo.

  • Primero obtenemos la referencia del contenedor del HTML donde deseamos colocar los elementos que crearemos con React. Nosotros lo guardamos en una constante llamada $app.
  • Luego utilizamos el método render() del ReactDOM que según la documentación de React recibe dos parámetros. El primer parámetro es el elemento que deseamos renderizar, que lo crearemos en el siguiente paso, y el segundo parámetro es el contenedor donde deseamos renderizar nuestro nuevo elemento. En nuestro caso utilizaremos el contenedor $app.
  • Para crear el elemento que deseamos renderizar debemos usar el método createElement() de React. Este método según la documentación oficial recibe tres parametros, el primero es necesario y los siguientes opcionales. El primer parámetro es el tipo de elemento que queremos crear, por ejemplo un "div". El segundo parámetro representa a los props, un concepto que lo veremos más adelante. El tercer y último parámetro son los objetos hijos que queremos crear dentro de este elemento. En nuestro caso solo imprimiremos el texto "AndyGeek" dentro de nuestro "div".
<script>
  const $app = document.getElementById("app");

  ReactDOM.render(React.createElement("div", null, "AndyGeek"), $app);
</script>

Esta es la manera como React crea elementos en el DOM utilizando solo dos métodos que estamos extrayendo de los CDNs que agregamos al proyecto. Si utilizamos una función que nos retorne el createElement podríamos reutilizarlo las veces que queramos, lo que nos lleva al concepto de componente o una forma básica de lo que en un futuro llamaremos componente de React. Sin embargo para lograr esto necesitamos crear elementos con estructuras más complejas que un simple texto.

3. Anidando elementos

Para crear estructuras más complejas usando createElement debemos lograr la anidación de los elementos que creamos. Para lograr esto debemos hacer uso del tercer parámetro de createElement que como dijimos nos permite anidar elementos hijos. Veamos la estructura de este método.

React.createElement(type, [props], [...children]);

Una particularidad de este método es que tiene la capacidad de no solo recibir tres parámetros si no de recibir infinitos parámetros. Pues tenemos dos casos al trabajar con este método, el primero es cuando esta función recibe tres parámetros donde el tercero es un arreglo [] y la segunda opción es enviarle la cantidad de parametros que queramos, pero a partir del tercer parámetro todos serán elementos hijos de nuestro elemento. Vemos un ejemplo ilustrativo de algo similar que podemos hacer solo con JavaScript.

function render(a, b, ...arg) {
  // Verificamos si el ultimo parámetro es un arreglo o no
  if (Array.isArray(arg[0])) {
    arg[0].forEach((element) => console.log(element));
  } else {
    arg.forEach((element) => {
      console.log(element);
    });
  }
}
// En ambos casos obtendremos el mismo resultado
render(0, 1, 22, 33, 44, 55, 66);
// A partir del tercer argumento se almacena en forma de arreglo [22,33,44,55,66]
// por lo que imprimimos loe elementos de arg

render(0, 1, [22, 33, 44, 55, 66]);
// El tercer argumento es [[22,33,44,55,66]] (un arreglo)
// por lo que imprimimos los elementos de arg[0]

Entonces si llevamos estas ideas al método createElement nosotros podemos anidar elementos de dos formas distintas. Pero para tener una vista más ordenada y entendible en el siguiente ejemplo usaremos una función que retorne un elemento createElement para así reutilizarlo en nuestro método createElement.

<script>
  const $app = document.getElementById("app");

  function myName() {
    var name = "AndyGeek";
    return React.createElement("h3", null, name);
  }

  ReactDOM.render(
    React.createElement("div", null, myName(), myName(), myName()),
    $app
  );
</script>

Lo mismo podemos lograr enviando los elementos hijos como un arreglo de elementos de la siguiente forma.

ReactDOM.render(
  React.createElement("div", null, [myName(), myName(), myName()]),
  $app
);

Sin embargo, obtendremos un error que lo solucionaremos en la siguiente parte de este tutorial utilizando los props.

Hasta ahora llamamos elementos a cada estructura que creamos utilizando createElement. Sin embargo, esta es una forma temprana de lo que es un componente de React por lo que ahora los llamaremos componente.

4. Los Props como parámetros de un componente

Los props son como los parámetros de una función, donde nuestros componentes son las funciones. Es la forma de comunicación que tienen los componentes en React. Así que nosotros utilizaremos a los props en el siguiente ejemplo para enviar a nuestro componente lo que queremos que este imprima en la pantalla del navegador.

const $app = document.getElementById("app");

// Devolvemos un H3 con texto en su interior
// Obteniendo el texto desde el parámetro props
function myName(props) {
  return React.createElement("h3", null, props.name);
}

ReactDOM.render(
  // Creamos un div con con varios myName en su interior
  // Donde a cada myName le enviamos un objeto
  // Estos objetos son los props
  React.createElement(
    "div",
    null,
    React.createElement(myName, { name: "Andy" }, null),
    React.createElement(myName, { name: "React" }, null),
    React.createElement(myName, { name: "AndyGeek" }, null)
  ),
  $app
);

Como puedes ver utilizamos el segundo parámetro del método createElement para enviar un objeto. El cual es recepcionado por la función myName por el parámetro props y luego utiliza su propiedad name para crear un elemento h3 con el texto de name en su interior. Los props son los parámetros que se pasan a los componentes mediante el segundo parámetro del método createElement.

Nosotros podemos crear props con más datos en su interior para luego enviarlos de la siguiente forma.

React.createElement(
  myName,
  { id: 1, name: "Andy", skill: "programming" },
  null
);

// Para luego utilizarlo dentro de nuestro componente
function myName(props) {
  return React.createElement("p", null, props.id, props.name, props.skill);
}

Ahora que ya sabemos como utilizar los props, ya podemos solucionar el error que obtuvimos en el ejemplo de la sección anterior. Ese error sucedió porque cuando colocamos los elementos hijos como un arreglo React lo identifica como si de una lista se tratase y los props de los elementos de una lista requieren una propiedad llamada key que es él que identifica a cada elemento de la lista como único elemento de la lista. Es por esto que debemos colocar una propiedad key en los props de cada elementos de la lista como en el siguiente ejemplo.

ReactDOM.render(
  React.createElement("div", null, [
    React.createElement(myName, { key: 1, name: "Andy" }, null),
    React.createElement(myName, { key: 2, name: "React" }, null),
    React.createElement(myName, { key: 3, name: "AndyGeek" }, null),
  ]),
  $app
);

5. Por qué JSX

Pues bien, como de seguro te diste cuenta, utilizar esta forma de anidación es muy tediosa y puede llevarnos a cometer errores al crear nuestros componentes en React. Imagínate entender la siguiente anidación.

ReactDOM.render(
  React.createElement(
    "div",
    null,
    React.createElement(
      "div",
      null,
      React.createElement("h2", null, "Titulo"),
      React.createElement(
        "ul",
        null,
        React.createElement("li", null, "Primero"),
        React.createElement("li", null, "Segundo"),
        React.createElement("li", null, "Tercero")
      )
    )
  ),
  $app
);

Es por eso que el equipo de Facebook detrás de React decidió crear un pseudo-lenguaje de programación llamado JSX, que React lo utiliza por su sintaxis sencilla para crear componentes. Este no es un lenguaje de programación solo es un lenguaje muy similar a la unión de HTML y JS que lo utilizamos solo por su sintaxis. Al fin y al cabo este lenguaje es traducido a JavaScript por un transpilador de código conocido como Babel. Veamos el código JSX del ejemplo de la sección anterior donde usamos props.

const $app = document.getElementById("app");

function MyName(props) {
  return <h1>{props.name}</h1>;
}

ReactDOM.render(
  <div>
    <MyName name="Andy" />
    <MyName name="React" />
    <MyName name="AndyGeek" />
  </div>,
  $app
);
Cuando usamos JSX si queremos colocar código JavaScript dentro de nuestra estructura HTML debemos usar las llaves { }, también debemos usarlas si queremos colocar alguna variable en la estructura misma o en algun atributo de las etiquetas HTML.

Como puedes ver la anidación ya no la tenemos que hacer mediante createElements simultáneos uno dentro de otro. En su lugar utilizamos un código muy similar a HTML que nos facilita su comprensión. Además los props los mandamos como atributos HTML. Esta es la magia de JSX y es la razón por la que se utiliza en React. Para hacernos la vida más fácil.

El que se encarga de llevar todo ese código a código JavaScript puro, que vemos a continuación, es Babel. Podemos transpilar el código y ver el funcionamiento de Babel desde su página web. Aquí podemos ver el código JavaScript transpilado que nos devuelve Babel y como ves nuevamente nos encontramos con el createElement de React.

"use strict";

const $app = document.getElementById("app");

function MyName(props) {
  return /*#__PURE__*/ React.createElement("h1", null, props.name);
}

ReactDOM.render(
  /*#__PURE__*/ React.createElement(
    "div",
    null,
    /*#__PURE__*/ React.createElement(MyName, {
      name: "Andy",
    }),
    /*#__PURE__*/ React.createElement(MyName, {
      name: "React",
    }),
    /*#__PURE__*/ React.createElement(MyName, {
      name: "AndyGeek",
    })
  ),
  $app
);
Pues bien y cómo utilizamos Babel en nuestro proyecto. Babel es un transpilador de código que nos permite traducir código de versiones actuales de JavaScript a versiones anteriores para que este pueda ser compatible con todos los navegadores. Sin embargo, React lo utiliza para transpilar el código JSX a JavaScript. Babel generalmente se utiliza con Webpack que es una tecnología que también utiliza React pero cuando hacemos uso del CLI para crear un proyecto. Por ahora, nosotros utilizaremos el CDN de Babel para usar JSX en nuestro script de HTML.

Para hacer esto primero agregamos el CDN de babel y luego agregamos el atributo type="text/babel" en nuestro script JavaScript para que Babel entienda que este script lo tiene que transpilar a JavaScript puro.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Hello World</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/babel.min.js"></script>
  </head>

  <body>
    <div id="app"></div>
    <script type="text/babel">
      const $app = document.getElementById("app");

      function MyName(props) {
        return <h1>{props.name}</h1>;
      }

      ReactDOM.render(
        <div>
          <MyName name="Andy" />
          <MyName name="React" />
          <MyName name="AndyGeek" />
        </div>,
        $app
      );
    </script>
  </body>
</html>

Y así ya podemos utilizar código JSX dentro de nuestro script de HTML y a partir de ahora solo utilizaremos JSX en este tutorial.

6. El primer Hook useState

Anteriormente en React solo se podía tener ciertas características si utilizábamos clases para crear un componente. Sin embargo, con la adición de los Hooks podemos tener estas mismas características sin necesidad de crear una clase para cada componente. Quizá esto de crear clases te suene un poco extraño ya que nosotros creamos nuestros componentes utilizando funciones pero es que ahora es más común crear componentes utilizando funciones. Pero veamos el siguiente ejemplo para ver como es crear un componente utilizando clases.

<script type="text/babel">
  const $app = document.getElementById("app");

  class MyName extends React.Component {
    render() {
      return <h1>{this.props.name}</h1>;
    }
  }

  ReactDOM.render(
    <div>
      <MyName name="Andy" />
      <MyName name="React" />
      <MyName name="AndyGeek" />
    </div>,
    $app
  );
</script>

Como ves no es la gran cosa, solo usamos una clase en lugar de una función que hereda sus propiedades de React.Component. Además utilizamos el método render() para colocar la estructura HTML que queremos utilizar. Por último, los props forman parte de la clase por lo que utilizamos this para llamarlos, no es necesario obtenerlos como parametros como hacíamos con las funciones. Lo demás es totalmente igual.

Ahora que ya sabemos que podemos crear componente utilizando clase, el siguiente concepto que debemos conocer es sobre el de state o estado. El state es un almacén de datos de un componente que además de ser mutable son autónomos. Así que aquí es donde podremos almacenar los datos de nuestros componentes y luego si los cambiamos esto se reflejará dentro de nuestra vista. Y como dije anteriormente el estado solo era posible utilizando clases, veamos como es crear el estado de un componente utilizando clases.

<script type="text/babel">
  const $app = document.getElementById("app");

  class MyName extends React.Component {
    constructor(props) {
      super(props);
      this.state = { number: 0 };
    }
    render() {
      return (
        <div>
          <h1>{this.props.name}</h1>
          <p>My number is {this.state.number}</p>
        </div>
      );
    }
  }

  ReactDOM.render(
    <div>
      <MyName name="Andy" />
      <MyName name="React" />
      <MyName name="AndyGeek" />
    </div>,
    $app
  );
</script>

Ahora si queremos reactividad en nuestra web debemos modificar el estado, para que luego se refleje dentro de nuestra web. Para esto debemos crear un método que se ejecute al interactuar con algún elemento de nuestra web como hacer click en algún botón. También debemos mencionar que para que esto suceda como deseamos debemos usar un método que ya está implementado en React, que es el setState. Este método nos permite modificar alguna propiedad de los props. Ejecutar setState también le ayuda a React a saber cuando hay un cambio de estado para volver a renderizar el elemento en pantalla. En el siguiente ejemplo creamos un botón que modifica el estado del componente.

<script type="text/babel">
  const $app = document.getElementById("app");

  class MyName extends React.Component {
    constructor(props) {
      super(props);
      this.state = { number: 0 };
    }
    addNumber() {
      this.setState({ number: this.state.number + 1 });
    }
    render() {
      return (
        <div>
          <h1>{this.props.name}</h1>
          <p>My number is {this.state.number}</p>
          <button onClick={() => this.addNumber()}>Click me</button>
        </div>
      );
    }
  }

  ReactDOM.render(
    <div>
      <MyName name="Andy" />
      <MyName name="React" />
      <MyName name="AndyGeek" />
    </div>,
    $app
  );
</script>
Dentro del botón utilizamos una función flecha o arrow function porque el onClick requiere un método que se ejecute al hacer click sobre él. Si colocamos la función directamente este se ejecutará también al momento de compilar el proyecto.

Ya vimos cómo son las cosas utilizando clases ahora volvamos a los componentes creados con funciones y a los Hooks Pues los Hooks nos permite usar este estado dentro de la función que ocupa nuestro componente, algo que no se podía anteriormente. Existen distintos Hooks para cada una de estas funcionalidades, pero useState es el Hook que nos permite tener estado dentro del componente así que lo utilizaremos en el siguiente ejemplo para almacenar un dato adicional.

<script type="text/babel">
  const $app = document.getElementById("app");
  const useState = React.useState;

  function MyName(props) {
    const [number, setNumber] = useState(0);

    return (
      <div>
        <h1>{props.name}</h1>
        <p>My number is {number}</p>
        <button onClick={() => setNumber(number + 1)}>Click me</button>
      </div>
    );
  }

  ReactDOM.render(
    <div>
      <MyName name="Andy" />
      <MyName name="React" />
      <MyName name="AndyGeek" />
    </div>,
    $app
  );
</script>

Para usar este Hook primero que todo debemos almacenarlo en alguna constante para que sea más fácil utilizarlo, en nuestro caso usamos la constante useState. Luego debemos crear una constante con un arreglo de dos elementos. El primer elemento representa al estado o una propiedad del estado y el segundo elemento representa a la función que podrá modificar ese estado. En nuestro ejemplo tenemos al estado number que solo puede ser modificado por el método setNumber(). Este arreglo lo igualamos al Hook useState() enviando como parámetro el estado inicial de nuestro estado number.

const useState = React.useState;
...
const [number, setNumber] = useState(0)

Entonces ahora ya podemos utilizar setNumber para cambiar aumentar el valor de nuestro estado number. Esto lo hacemos mediante un botón, de la siguiente forma.

<button onClick={() => setNumber(number + 1)}>Click me</button>

Listo!! con esto ya obtuvimos reactividad en nuestro proyecto Web. Y también llegamos al final de este tutorial donde analizamos como es que React crea los componentes en el DOM, por qué utiliza JSX y por qué los Hooks vinieron a salvarnos la vida de un mundo lleno de clases. Soy AndyGeek y hasta el próximo tutorial.