0% encontró este documento útil (0 votos)
117 vistas

Tutorial de React

El documento presenta una introducción a React que incluye: 1) una explicación de qué es JSX y cómo permite mezclar JS y HTML, 2) una descripción de las características principales de ECMAScript 6 como const, let, arrow functions y destructuring que facilitan el desarrollo en React, y 3) un resumen de cómo importar y exportar módulos en JavaScript.
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
117 vistas

Tutorial de React

El documento presenta una introducción a React que incluye: 1) una explicación de qué es JSX y cómo permite mezclar JS y HTML, 2) una descripción de las características principales de ECMAScript 6 como const, let, arrow functions y destructuring que facilitan el desarrollo en React, y 3) un resumen de cómo importar y exportar módulos en JavaScript.
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 41

Tabla de contenido: Tutorial de

React
1. ¿Qué es JSX?
2. ECMAScript 6. Lo Básico
3. React API y ReactDOM
4. Componente-zación y Create React App — Código
fuente: GitHub
5. Propiedades y Estado de los Componentes — Código
fuente: GitHub
6. Eventos en React — Código fuente: GitHub
7. Ciclos de Vida de los Componentes de React
1. ¿Qué es JSX?

JSX es una extensión de sintaxis de JavaScript que nos


permite mezclar JS y HTML (XML), de ahí su nombre
JavaScript XML.

Esta extensión nos facilita la vida pues nos permite escribir


un código más limpio, sin tantas repeticiones (DRY), y con
muy pocos factores o condiciones a tener en cuenta.

¿Y BabelJS?
Nuestro código JSX es compilado por un “Transpiler”, que
quiere decir que toma un código de un lenguaje y lo compila
al mismo código en otro lenguaje. Este “Transpiler”,
llamado Babel JS, compila el código JSX a código JS. (Más
sobre source-to-source compiler)

Esto nos permite:

1. Asignar expresiones JSX a variables.


2. Pasar expresiones JSX como argumentos de funciones.
3. Retornar expresiones JSX de ciclos, condicionales y
funciones.

¿Cómo funciona?
Las expresiones JSX se convierten en llamados regulates de
funciones de JavaScript que finalmente evalúan a un Objeto.
<h1>Hello world!</h1>
evaluaría a algo como:
React.createElement("h1", null, "Hello world!");

para hacer sus propias pruebas puede visitar Babel Try it


Out.

React.createElement es el método que se invoca cada vez


que vamos a crear un elemento. Este método recibe 3
argumentos. El primero es el tipo o una cadena de texto
(String) en este caso “h1”, el segundo son los atributos o
propiedades del elemento en este caso null, y por último,
desde el tercer argumento hacia adelante, los hijos del
elemento siendo otros elemento de
React React.createElement(); o una cadena de texto que en este
caso sería “Hello world!”.

¿Qué debemos de tener en cuenta a la hora


de usar JSX?
• Hay ciertos atributos en HTML que son los mismos que
palabras reservadas de JS, por eso al momento de usar
estos atributos, tendríamos que cambiarlos en nuestro
JSX. Ejemplo:class por className , for por htmlFor.
• También debemos tener en cuenta que la sintaxis de JSX
es más cercana a la sintaxis de JS que de HTML, por esta
razón, comparten la misma convención al momento de
nombrar funciones, variables, etc. Esta convención se
llama “camelCase” donde la primera palabra se escribe
con minúscula y sin dejar espacio se escribe la segunda
palabra con mayúscula inicial y así sucesivamente. Esta
es la razón de className y htmlFor.
• Todas las etiquetas se deben cerrar ya sea con una
etiqueta de cierre<div></div> o por auto cerrado <img />.
• JSX sólo permite retornar un único elemento, por lo que
todos los elementos deben estar envueltos dentro de un
mismo elemento.
<div>
<h1>Hello world!</h1>
<p>from Colombia</p>
</div>

• Podemos usar corchete ( { } ) para insertar expresiones


de JavaScript en nuestro código JSX.

Para demostrarles como funciona esto, primero declaremos


una variable:
let name = “Simon”;

Luego podría pasar esta variable a un elemento de React de


la siguiente manera :
<h1>{name}</h1>

Esto reemplazará los corchetes por el valor de la variable


name resultando en:
<h1>Simon</h1>

• Al momento de crear elemento y asignarles propiedades


se utiliza alguna de las siguientes dos opciones. Una
cadena de texto, o una expresión de JS envuelta entre
corchetes. Para esta última opción, hay que recordar que
no se deben poner comillas dobles (“) o sencillas (‘) al
momento de asignarle un valor a los atributos.

En resumen. Aunque no es obligatorio usar JSX con React,


es una sintaxis de la que podemos apoyarnos y sacarle
bastante provecho. Esta nos permitirá crear aplicaciones
más complejas de una manera más fácil y rápida.
Por último, ¿Qué creen que resultaría al compilar el
siguiente código?
<div class="container">
<h1 id="title">Lorem ipsum</h1>
<img
src="https://upload.wikimedia.org/wikipedia/commons/e/eb/Ash_
Tree_-_geograph.org.uk_-_590710.jpg" alt="tree" width="30px"
height="30px" />
<p style="color: blue;">Lorem ipsum dolor sit amet,
consectetur adipiscing elit, sed eiusmod tempor incidunt ut
labore...</p>
</div>

Aquí pueden ver la respuesta.

Extra: mira cómo compila el objeto para los atributos y


cómo agrega varios elementos como hijos del tag div.
2. ECMAScript6. Lo Básico
La semana pasada terminamos hablando de Babel JS, el
transpilador que nos permite usar JSX junto a React. Lo
cierto es que este transpilador tiene más funciones que nos
permiten extender y hacer uso de muchas de
las nuevas funcionalidades de JavaScript, así como
también nos brinda uniformidad y compatibilidad con más
plataformas.

Hoy vamos a hablar de ECMAScript6 o ECMAScript2015


o ES6 (como lo llamaremos en el resto de este artículo) y de
las funcionalidades que usaremos con mayor frecuencia al
momento de programar en React.

Nuevas variables
ES6 nos trae dos nuevas formas de declarar
variables, const y let. La gran diferencia entre estas 2 formas
de declarar variables y la forma antigua, var es que
el scope de var es hacia una función mientras que
el scope de const y let es hacia un bloque de código.

Además de lo anterior const tiene un característica extra y es


que solo se le puede asignar un valor una única vez.
Teniendo en cuenta que cuando el valor es un objeto o un
arreglo, el objeto o el arreglo en sí, pueden ser modificados.
{
let es6Variable = 15;
}
const es6Constant = 'Hello world';
const newArray = [1, 2, 3];
Si intentamos acceder al valor de es6Variable por fuera de su
bloque, por ejemplo console.log(es6Variable); obtendríamos un
error de referencia pues la variable es6Variable no está
definida por fuera de su bloque. Lo mismo pasaría si
hiciéramos el mismo ejercicio con const.

Así mismo, si intentamos modificar la


constante es6Constant de la siguiente manera es6Constant = 'Hello
Simon'; obtendríamos un error en tiempo de compilación
puesto que las constantes son una referencia de solo
lectura. Por otro lado, si intentamos modificar algún
elemento del arreglo newArray de la siguiente
manera newArray[1] = 5; o newArray.push(4); el valor final de la
constante sería [5, 2, 3, 4], nos permite modificar
arreglos u objetos, mas no hacer reasignaciones.

El código anterior, después de pasar por BabelJS, compilaría


a:
{
var es6Variable = 15;
}
var es6Constant = "Hello world";
var newArray = [1, 2, 3];

Arrow functions
se usan para definir funciones
arrow functions
anónimas con 2 grandes características que la diferencia
de la forma tradicional de definir una función (con la
palabra clave function).

1. thises la misma referencia dentro y fuera de


la función. En otras funciones this se puede
conectar (bind) con otros objetos. Lo que quiere
decir, cuando se hace referencia a this dentro de
un arrow function JavaScript empezará a buscar
un scope más arriba cada vez hasta encontrar el
valor de referencia de this (por defecto el global
scope).

2. El objeto arguments no está definido. Para lograr lo


mismo debemos usar el spread operator.
const es6Function = (...args) => {
return arg[0] * arg[1];
};

Características:

• si solo reciben un argumento es posible omitir los


paréntesis de los argumentos.
const es6Function = onlyArgument => {
console.log(onlyArgument);
return onlyArgument;
};

• si se omiten los corchetes el código, se ejecuta


como una expresión y lo que evalúe esta expresión,
es lo que retornará la función. Esto solo aplica
para funciones de una línea, si se requiere agregar
varias líneas de código, debemos usar corchetes y
usar la palabra clave return explícitamente.
const es6Sum = (num1, num2) => num1 + num2;
es6Sum(1, 2); //3

Destructuring
Una manera de asignar múltiples llaves o
propiedades de un objeto o arreglo simultáneamente.
Sé que no es muy claro, pero este es uno de esos momentos
en que definitivamente el código tiene muchísimo más
sentido que la teoría.
const newArray = [1, 2, 3];
let [one, two, three] = newArray;const newObject = {
name: 'Simon',
hobby: 'React'
};
let { hobby, name } = newObject;
En este código estamos creando tres variables one, two, three y
a cada una le estamos asignando cada uno de los valores
correspondientes del arreglo. Lo mismo para newObject,
creamos 2 variables hobby y name y les asignamos a cada una la
llave correspondiente. Esto sería lo mismo que el siguiente
código:
var newArray = [1, 2, 3];
var one = newArray[0],
var two = newArray[1],
var three = newArray[2];var newObject = {
name: "Simon",
hobby: "React"
};
var hobby = newObject.hobby,
var name = newObject.name;

Importaciones y Exportaciones
y export proveen un manejo más avanzado de módulos
import
en JavaScript. Es posible importar/exportar funciones,
objetos o valores primitivos. Existen 2 maneras de
hacerlo: nombradas y por defecto.

• exportaciones/importaciones nombradas: son


muy buenas para exportar/importar varios
valores al mismo tiempo. Es necesario usar el
mismo nombre para exportar como para
importar.
export { functionOne, objectTwo, valueThree }; // inside
app.jsimport { functionOne, objectTwo, valueThree } from
'app'; // inside other.js

• exportaciones por defecto: solo puede haber una


por módulo. se puede importar con cualquier
nombre, no tiene que se el mismo que se usó para
la exportación.
export default ClassDefault; // inside app.jsimport Class
from 'app'; // inside other.js

También es posible hacer una mezcla de ambos métodos:


// inside app.js
const number = 15;
export number;const es6Function = (num) => num;
export default es6Function;// inside other.js
import es6Function, { number } from 'app';

Parametros o argumentos por


defecto
Es posible asignarle un valor predeterminado a los
argumentos de una función a la hora de declarar la misma.
Estos valores son tomados cuando al momento de invocar
una función, sus valores son indefinidos.
const defaultParameters = (num1=5, num2=7) => {
return num1 + num2;
};console.log(defaultParameters(1, 2)); // 1 + 2 = 3
console.log(defaultParameters(1)); // 1 + 7 = 8 (7 por
defecto)
console.log(defaultParameters()); // 5 + 7 = 12 (5 y 7 por
defecto)

Clases
Las clases, creadas con la palabra clave class no son más que
funciones. En realidad, el principal objetivo de las clases es
cambiar un poco (o mucho), para bien o para mal,
la sintaxis existente de objetos, prototipos y
herencia.

Durante este curso aprenderemos más sobre esta sintaxis,


¿Qué podemos y qué no podemos hacer? y los beneficios de
esta al momento de usar React.

Template literals
Son cadenas de texto que nos permiten:
• escribir en varias líneas.
const es6String = `
Hello world,
I'm a multiline
Template literal.
`;

Anteriormente:
var oldString = "\n Hello world,\n I'm a multiline\n
Template literal.\n";

• interpolar o insertar código en la misma


cadena de texto.
const name = 'Simon';
const es6String = `Hello ${name}`;console.log(es6String); //
Hello Simon

En resumen
Al igual que con JSX, el uso de ES6 no es obligatorio al
momento de usar React. Pero poco a poco iremos viendo sus
beneficios. ES6 nos brinda un amplio repertorio de nuevas
funcionalidades y nuevas formas de hacer cosas con
JavaScript.
3. React API y ReactDOM
En los últimos post hablamos de JSX y de ES6, pero cuando
hice una promesa en “Y así empieza el 2018…”, dije que el
blog que crearía, sería sobre React. Y aunque estos temas
están directamente relacionados con React, creo que ha
llegado la hora de tocar el tema en cuestión. Ahora es el
momento en que empezamos a hablar de React.

React es una librería de JavaScript, esta librería trabaja


eficientemente sobre el DOM haciendo que las
actualizaciones que se deben hacer en la interfaz gráfica, se
hagan de manera más rápida y fluida.

Instalando React
Para trabajar con React tenemos dos opciones, usar
un CDN o si tenemos acceso a npm o yarn (gestores de
paquetes, que nos permiten manejar las dependencias de
nuestro proyecto) y conocimientos de ES6 básico, el cual
ahora tenemos, podemos importar el paquete de React
usando import React from 'react';. Este último será el método
que usaremos de ahora en adelante.

y yarnson manejadores de paquetes, que nos permiten


npm
manejar las dependencias de nuestro proyecto

Cuando hacemos importaciones con ES6, debemos tener en


cuenta lo siguiente: las rutas a las importaciones desde
archivos propios deben ser relativas (a menos que lo
configuremos de manera diferente). Miremos el siguiente
ejemplo:

Teniendo en cuenta la siguiente estructura de carpetas


node_modules
- ...muchas sub-carpetas
app
- app.js
helpers
- helpers.js

Si queremos importar una pieza de código


desde helpers hacia app lo debemos hacer de la siguiente
manera:
import * from '../app/app.js';

Cuando vemos importaciones, en general, con rutas


absolutas, es porque estamos importando un paquete de
JavaScript de la carpeta node_modules como en el caso de import
React from 'react';. Estos paquetes debemos instalarlos
previamente usando npm o yarn.

Para instalar React usamos cualquiera de los siguientes dos


comandos:
npm install --save react
yarn add react

También debemos tener en cuenta que en todo archivo que


vayamos a usar React, debemos importar React. La razón
para esto es que, si recordamos como funciona JSX, después
de ser compilado, siempre resultará en la
forma React.createElement('Elemento', { atributos }, hijos);. En el
código anterior React hace referencia al API de React al que
obtenemos acceso al momento de importar su paquete.

Yo he visto que utilizan ReactDOM


Este paquete, también fundamental para el funcionamiento
de nuestra aplicación, nos da acceso a funcionalidades
específicas para trabajar sobre el DOM.
Podemos instalar ReactDOM con alguno de los siguientes
comandos
npm install --save react-dom
yarn add react-dom

El método que veremos con mayor frecuencia es render().


Este método recibe 2 argumentos: El elemento de React que
se va a renderizar y elemento de HTML en el cual se va a
insertar ese elemento.
const element = React.createElement('h1', { className:
'title' }, 'Hello world');ReactDOM.render(element,
document.getElementById('app');

El código anterior, añadirá el elemento <h1 class="title">Hello


world</h1> a un elemento del DOM con id="app" . Resultando en
algo como:
<div id="app">
<h1 class="title">Hello world</h1>
</div>

En resumen
Mientras React nos provee de métodos para crear los
elementos que se van a renderizar en nuestro HTML,
ReactDOM nos provee los métodos que nos permitirán
llegar a un punto donde se encontrará nuestro código con
nuestro HTML.

Creo que ahora tenemos suficientes bases para empezar a


jugar un poco con React. Soy de los que cree que programar
se aprende es programando, por lo que de ahora en
adelante, estaremos aprendiendo conceptos mientras
programamos.
4. Componente-zación y Create
React App
React nos permite dividir nuestra interfaz gráfica en varios
componentes. Un componente no es más que cada parte en
la que queremos dividir esa interfaz gráfica. Cabe resaltar
que no solo la interfaz puede ser dividida en componentes,
sino que también los componentes en sí.

La idea principal detrás de los componentes es tener piezas


de código que sean tanto independientes como reutilizables,
y que manejen su propio estado para que puedan ser
combinados de muchas maneras para así, generar interfaces
gráficas complejas.

Create React App


Para nuestros ejemplos de hoy, vamos a estar trabajando
con una herramienta llamada create-react-app. Esta
herramienta, desarrollada por ingenieros de Facebook, nos
permite empezar un nuevo proyecto de React sin pasar
mucho tiempo pensando en la configuración.

Tengamos en cuenta que, aún teniendo a nuestra


disposición esta herramienta, siempre es bueno conocer la
forma en cómo esta está configurada y por su puesto, saber
configurar un proyecto por nuestra cuenta. Aunque este no
sea el tema de hoy, la idea es abordar todos estos temas en
futuros artículos. (ver qué incluye create react app).
Para instalar esta herramienta, corremos el siguiente
comando en nuestra consola:
npm install --global create-react-app

Esto nos dará acceso al siguiente comando en nuestra


consola:
create-react-app _my-new-app-name_

El cual correremos estando ubicados en la carpeta en la cual


queremos iniciar nuestro proyecto. Esto crea una carpeta
con la siguiente estructura:
_my-new-app-name_
├── README.md
├── node_modules
├── package.json
├── .gitignore
├── public/
│ └── favicon.ico
│ └── index.html
│ └── manifest.json
└── src/
└── App.css
└── App.js
└── App.test.js
└── index.css
└── index.js
└── logo.svg
└── registerServiceWorker.js

Poco a poco iremos viendo cada uno de estos archivos más a


fondo para ir incrementando nuestro conocimiento sobre
React. Por ahora, nos vamos a concentrar solo en los
archivos public/index.html, src/index.js, y src/App.js. En los
primeros 2 vamos a dar una vista rápida para entender, en
un proyecto real, cómo funciona ReactDOM, mientras que el
último, será en el cual escribiremos nuestro código.
ReactDOM
Lo importante que quiero que veamos para familiarizarnos y
siempre tener en cuenta en los archivosindex.html y index.js es
el siguiente código:

En el body de nuestro HTML veremos:


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

Este será el elemento que utilizaremos como punto de


entrada para nuestro JavaScript.

Al final de nuestro JS veremos:


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

Esto, según lo aprendido en React API y ReactDOM,


renderiza el componente App en nuestro div con
identificador root. Por ahora, no modificaremos esta
configuración, mejor aún, nos vamos a aprovechar de ella,
por lo que estaremos trabajando nuestros ejemplos en el
componente App.js.

También podremos ver en este mismo archivo que el


componente App está siendo importado al principio del
código de la siguiente manera:
import App from './App';

Componentes funcionales
Se les llama de esta manera porque son funciones de
JavaScript. Lo que las hace ser componentes de React, es
que reciben props o propiedades (argumento de la función) y
retorna JSX, o mejor dicho un elemento de React.
Un componente funcional se vería de la siguiente forma:
function Button() {
return <button className='add-button'
type='button'>+</button>
}

O cómo vimos en ES6 lo básico:


const Button = () => {
return <button className='add-button'
type='button'>+</button>
}

Con este código estamos creando un botón con clase add-


button y el signo más ‘+’ como contenido.

Para utilizar este nuevo elemento de React en nuestro


código, utilizaremos el tag <Button /> que nos creará el mismo
botón cada vez que lo invoquemos.

Componentes clase
Utilizan la sintaxis de class de ES6, teniendo en cuenta los
siguientes puntos:

1. Los componentes clase deben extender de React.Component o


de Component, dependiendo de cómo estemos importando
React. import React from 'react'; e import React, { Component }
from 'react'; respectivamente.

2. Debe tener la función render(), analiza las propiedades


o props y debe retornar un elemento válido de React, una
cadena de texto, un número, un booleano, o null (o al
menos eso es lo que nos interesa por ahora).

Ejemplo
Para ver los componentes en acción, vamos a borrar el
contenido del archivo App.js y App.css y agregaremos nuestro
propio código.

Siempre empezamos importando React y paquetes


necesarios para que funcionen nuestros componentes. En
este caso, vamos a importar aparte de React, nuestro archivo
CSS.
import React, { Component } from 'react';
import './App.css';

Luego agregaremos nuestro componente de botón que


creamos anteriormente a nuestro código:
const Button = () => {
return <button className='add-button'
type='button'>+</button>
}

Ahora vamos a crear un componente clase llamado App que


renderizará, en este caso, 2 de nuestros componentes Button.
Si queremos renderizar más botones, lo único que debemos
hacer, es agregar más etiquetas <Button /> a lo que sea que
retorne nuestra clase.
class App extends Component {
render() {
return (
<div>
<Button />
<Button />
<div>
);
}
}

Quiero resaltar dos cosas que son importantes a tener en


cuenta del anterior código:

1. Cuando vamos a retornar JSX en varias líneas, con el fin


de que el código se vea más limpio, escribiremos los
elementos a partir de la siguiente línea del return y por
esta razón, se hace necesario el uso de paréntesis para
envolver el código JSX.
2. Lo que nos permite diferenciar un elemento HTML y un
elemento de React, es que los elementos de React se
escriben usando mayúscula inicial, por eso, aunque el
elemento <button /> ya existe en HTML, podemos hacer
uso de nuestro elemento <Button />.

Por último exportamos el componente App para que pueda


ser importado desde index.js y ser renderizado por
ReactDOM.
export default App;

Corremos el comando yarn start o npm start en nuestra consola


parados sobre la carpeta de nuestro proyecto, abrimos
nuestro navegador, navegamos a localhost. Ahora vemos
nuestros 2 botones.

Se pueden mejorar
¿Recuerdan que les pedí anteriormente borrar el contenido
del archivo App.css? Vamos a agregar los siguientes estilos
para que nuestros botones se vean un poco más bonitos ;)
(siéntanse libres de modificar los estilos).
.add-button {
padding: 10px 20px;
font-size: 20px;
color: #fff;
background-color: #4682b4;
border-color: #586D7F;
border-radius: 10px;
}.add-button:hover {
background-color: #63B8FF;
border-color: #63B8FF;
}.add-button {
outline: none;
}
En conclusión
Create React App es una herramienta que nos permite
empezar un proyecto desde cero, sin mayores
preocupaciones por la configuración del mismo (sin dejar de
lado la importancia de conocer esta ni la manera de hacerlo
por nosotros mismos).

Gracias a esto, hoy vimos un ejemplo practico de ReactDOM


y creamos 2 componentes. Uno funcional, nuestro botón
‘agregar’; y un componente clase, encargado de contener
nuestra aplicación y renderizar nuestros botones.

Código fuente: GitHub


5. Propiedades y Estado de los
componentes
Hoy estaremos trabajando sobre el mismo ejercicio que
terminamos está semana (aquí). En este ejercicio creamos: 2
componentes, un botón y un componente contenedor para
la aplicación. Terminamos mostrando 2 botones con el signo
‘+’ a nuestra interfaz gráfica.

Aún podemos hacer muchos cambios para mejorar nuestros


componentes. Por ejemplo, ¿Qué tal si queremos que los
botones no solo muestren el signo más, sino cualquier
símbolo, texto, o hasta números que nosotros queramos?
¿Cómo haríamos en el caso que quisiéramos almacenar un
valor importante para nuestro componente? Como el valor
de un contador. Todo esto y más lo vamos a poder resolver
por medio de props y state, propiedades y
estado respectivamente

Si quieres ver los pasos que seguimos en este proyecto y


quieres saber un poco más sobre componentes y create
react app, puedes visitar este artículo.

Lo que haremos
1. Cambiaremos el contenido de los botones para que
uno muestre el signo ‘+’ y el otro el signo ‘-’, y cada uno
de los botones deberá mostrarse de un color diferente.
Esto sin tener que crear un nuevo componente.
2. Mostraremos un contador en pantalla.
3. Agregaremos funcionalidad a los botones para que nos
permita incrementar y disminuir el contador. No
usaremos los eventos de React, por ahora utilizaremos
eventos de JavaScript.

Props
Son las propiedades que se le pasan desde un componente
padre a un elemento hijo y solo el padre las puede modificar.
Estas propiedades son como los atributos HTML y
se configuran al momento de “instanciar” un
componente.

Recordemos JSX, un elemento en React compilaría en el


siguiente código:
React.createElement('h1', { className: 'my-class' }, 'Hello
world');

Las props de un elemento son el objeto que le pasamos al


método createElement como segundo argumento.
También hay que tener en cuenta que del
tercer argumento en adelante, que son los hijos que va a
renderizar el componente, también son propiedades, por
lo que el elemento anterior también se podría escribir de la
siguiente manera:
React.createElement('h1', { className: 'my-class', children:
'Hello world' });

o
<h1 className='my-class'>Hello world</h1>
<h1 className='my-class' children='Hello world' />

Siendo mucho más clara la primera forma en cada caso.


Instanciando nuestro componente
¿Y esto cómo nos puede ayudar a resolver nuestro dilema de
cambiar lo que muestra nuestro componente cada vez que lo
llamamos? Averigüémoslo haciendo unos cuantos cambios
en nuestro proyecto.

Hoy vamos a separar nuestros componentes, para dejar


clara la diferencia entre ellos. Para ello, creamos la
carpeta Button dentro de src y los
archivo Button.js y Button.css dentro de la carpeta esta,
pasamos los estilos al archivo CSS y nuestro componente
(función) Button al nuevo archivo JavaScript. Deberá quedar
algo como:
import React from 'react';
import './Button.css';const Button = () => {
return (
<button
className='add-button'
type='button'
>
+
</button>
);
}export default Button;

Ya hemos visto anteriormente cómo haríamos para


pasarle props a un componente. En el caso del botón,
queremos cambiar tanto el contenido como el color de fondo
y agregarle funcionalidad. Para esto vamos a definir 3
propiedades. primary, que sera un booleano para validar si el
botón es primario o no, y con respecto a
esto cambiaremos el color del background; className,
que nos permitirá agregar una clase extra a nuestro
componente (en este caso para agregarle eventos de
JavaScript); y children, que será el contenido del botón.
<Button
className='js-increment'
primary={true}
>
+
</Button>
<Button
className='js-decrement'
primary={false}
>
-
</Button>

Obteniendo las props


Para acceder a las props de un elemento lo hacemos de la
siguiente manera:

1. Agregamos parámetro props a nuestra función.


2. props es un objeto, por lo tanto podemos acceder a los
valores por medio de dot notation, como lo haríamos con
cualquier otro objeto. eg: props.primary.
const Button = (props) => {
const bgColor = props.primary ? '#4682b4' : '#C0625E';
return (
<button
className={`add-button ${props.className}`}
type='button'
style={{ backgroundColor: bgColor }}
>
{props.children}
</button>
);
}export default Button;

Destructuring props
Podemos aprovecharnos de destructuring de ES6. Ya que
sabemos con certeza cuales van a ser las propiedades que
recibirá nuestro componente, podemos cambiar nuestro
código por alguna de las siguientes 2 opciones:
const Button = (props) => {
const { primary, className, children } = props; ...
}

o
const Button = ({ primary, className, children}) => {
...
}

Cualquiera de las 2 formas nos permite cambiar la manera


como invocamos las propiedades dentro de nuestro
componente, de props.primary a solo primary, por ejemplo.

En caso de querer acceder los props en un componente


clase, los haríamos de la siguiente manera:
class Elem extends Component {
constructor(props) {
super(props);
} render() {
...
this.props.someProp
...
}
}

El constructor es el método que se invoca cada vez que


creamos una nueva instancia del componente, en este
caso Elem.

super es un método que invoca al constructor del padre, en


este caso Component. Para el correcto funcionamiento de
React, siempre que exista el método constructor, se debe
invocar el método super.

Nuestro componente final:


import React from 'react';
import './Button.css';const Button = ({ primary, className,
children }) => {
const bgColor = primary ? '#4682b4' : '#C0625E'; return (
<button
className={`add-button ${className}`}
type='button'
style={{ backgroundColor: bgColor }}
>
{children}
</button>
);
}export default Button;
State
El estado, a diferencia de las propiedades es interno, y al
igual que estos es un Objeto.

El estado no debe ser modificado por el padre del


componente sino por métodos del mismo componente.
Debemos tener en cuenta que el estado no se debe mutar,
por lo que hacer this.state.myVar =
'something' esta prohibido. Para esto, React nos provee un
método que nos permite modificarlo, setState({ newState
});.

Como el estado se debe inicializar con el componente, el


objeto state se define en el constructor del componente.
El estado se puede utilizar únicamente en componentes
clase. En nuestro ejemplo, vamos a agregar la
llave counter para almacenar el estado del contador, de la
siguiente manera:
...
import Button from './Button/Button';class App extends
Component {
constructor(props) {
super(props); this.state = {
counter: 0,
}
} ...
}export default App;

Y vamos a mostrar este estado en nuestra vista,


agregando this.state.counter. El componente App se vería de
la siguiente forma (después de unos retoques y algunos
cambios para agregar estilos):
class App extends Component {
... render() {
return (
<div className="App">
<div className='counter'>
<div className='counter__state'>
{this.state.counter}
</div>
<div className='coutner__buttons'>
<Button
className='js-increment'
primary={true}
>
+
</Button>
<Button
className='js-decrement'
primary={false}
>
-
</Button>
</div>
</div>
</div>
);
}
}

Vimos anteriormente que tenemos que usar un método que


React nos provee para poder modificar el
estado, this.setState({ newState });. Este método recibe
como argumento un nuevo objeto, o una función callback.
Lo que hace este método es crear un nuevo objeto, agregarle
todas las llaves y valores del estado inmediatamente
anterior, y luego modifica las llaves y valores que le pasamos
a la función como nuevo estado. Esto nos permite
mantener la trazabilidad del estado, cumpliendo con una
de sus principales características, el estado debe ser
inmutable.

Este método lo invocaremos al hacer click en alguno de


nuestros botones:
onIncrementClick = () => {
this.setState({
counter: this.state.counter + 1,
});
}onDecrementClick = () => {
this.setState({
counter: this.state.counter - 1,
});
}
Estas funciones modifican nuestro contador agregando o
disminuyendo en 1 el estado (counter), dependiendo del
botón que presionemos.

Agreguemos este código a nuestro componente:


class App extends Component {
constructor(props)

componentDidMount() {
const increment = document.querySelector('.js-
increment');
const decrement = document.querySelector('.js-
decrement'); if(increment && decrement) {
increment.addEventListener('click',
this.onIncrementClick);
decrement.addEventListener('click',
this.onDecrementClick);
}
} onIncrementClick = () => {
this.setState({
counter: this.state.counter + 1,
});
} onDecrementClick = () => {
this.setState({
counter: this.state.counter - 1,
});
} render()
...
}

Por ahora, ignoremos lo que hace el


método componentDidMount() y enfoquémonos en lo que
estamos haciendo en él.

Seleccionamos cada uno de nuestros botones, les


agregamos a cada uno una función que se debe correr en el
momento que le damos click, modificando el estado cada vez
que lo hacemos.

Por último, agregamos los siguientes estilos a App.css:


.App {
display: flex;
width: 100%;
height: 100vh;
justify-content: center;
align-items: center;
}.counter {
border: 2px solid #333;
border-radius: 6px;
padding: 20px;
}.counter__state {
box-sizing: border-box;
width: 100px;
height: 100px;
display: flex;
justify-content: center;
align-items: center;
font-size: 45px;
}

Y así se vería nuestra aplicación después de los pequeños


cambios de hoy:

En resumen
Las propiedades o props son externas al componente, se
configuran y se modifican desde el padre, y nunca desde el
mismo componente.

El estado o state es interno del componente, se configuran


en la constructor y se modifican desde el mismo
componente, usando this.setState(). Recuerda que no
debemos modificar los valores del estado directamente.

Por último, cabe resaltar que React es inteligente y sabe


cuando cambian alguno de estos 2 objetos (props o state).
En el instante que estos cambian React vuelve a
renderizar los componentes necesarios con los nuevos
valores.

Código fuente: GitHub


6. Eventos en React
La forma como manejamos eventos en React es muy
parecida a la forma en como los manejamos sobre el DOM.
<div onclick="handleClick()">click me</div>function
handleClick() {
alert('clicked'); return false:
}

Esta sería la forma como registramos un evento sobre


nuestro div. Para hacer lo mismo en React tenemos que
hacer los siguientes cambios:

1. El nombre del evento tiene que ser camelCase y no


minúscula sostenida.
2. Al evento se le pasa la función y no una cadena de texto.
3. En react si quieres prevenir un comportamiento por
defecto o la propagación de un evento debes hacerlo
explícitamente llamando los métodos preventDefault() y
stopPropagation() respectivamente.
<div onClick={handleClick}>click me</div>function
handleClick(event) {
alert('clicked'); event.preventDefault();
event.stopPropagation();
}

Eventos sintéticos
En este caso event ese un evento sintético de React, en
React todos los manejadores de eventos son instancias
de SyntheticEvents. Los eventos sintéticos son
una envoltura de los eventos nativos del navegador, por lo
que estos eventos cuentan con la misma interfaz de los
eventos nativos, como por
ejemplo preventDefault() y stopPropagation(), con la ventaja de
que todos estos eventos funcionan idénticamente en la
mayoría de los navegadores.

Eventos disponibles
React incluye eventos de teclado como onKeyUp,
onKeyPress, onKeyDown; de mouse como onClick,
onMouseMove, onDragOut, onDrop, etc.; de formularios,
como onChange, onInput, onInvalid, onSubmit; y muchos
más eventos que puedes ver en React Docs.

Si tenemos que usar un evento que no está en este listado


de eventos, lo tendríamos que hacer de la manera como lo
haríamos sin React. Registrando el evento desde el DOM o
con JavaScript usando addEventListener. Con React
generalmente no necesitas llamar este método para agregar
un evento al DOM después que el elemento es creado.
Mejor, el evento se puede agregar al elemento cuando este
es instanciado.

Vamos a refactorizar un poco


nuestro contador (GitHub).
Empecemos por con nuestro componente de botón
en Button.js. La función que vamos a invocar va a estar en el
padre, en este caso App. Lo que vamos a hacer es recibir el
manejador del evento por props y escuchar el evento desde
nuestro componente.

Los cambios que vamos a hacer son:

• agrega la propiedad onClick al objeto props de nuestro


botón de la siguiente manera:
const button = ({ primary, className, children, handleClick
}) => {
...
}

• Agregamos una nuevo atributo a nuestro botón, que


será el encargado de escuchar el evento de React, y este
recibirá la función que declaramos en el padre, que
recibiremos por medio del objeto props:
return (
<button
...
onClick={handleClick}
>
{children}
</button>
);

El resultado final sería algo como:


Button component

Ahora vamos a hacer los cambios necesarios en nuestro


componente App.

• Primero vamos a eliminar todo el


método componentDidMount(), en este método estamos
agregando los eventos a nuestro DOM por medio
de addEventListener(), pero ahora sabemos que React nos
permite agregar estos eventos al momento de instanciar
nuestro componente.
• Luego vamos a agregar a cada botón,
una propiedad handleClick a la que le pasaremos la
función correspondiente que se encargara de manejar
el evento click en cada uno de ellos.
<Button
...
handleClick={this.onIncrementClick}
>
...<Button
...
handleClick={this.onDecrementClick}
>
...
Debemos tener en cuenta lo siguiente, es muy común que
los manejadores de eventos sean métodos dentro de
nuestras clases, como en el caso
de onIncrementClick() y onDecrementClick().

Creando conexiones
Cuando invocamos una función como lo hicimos
anteriormente handleClick={this.onIncrementClick}, this,
normalmente, tendría un valor undefined, ya que las clases no
crean ninguna conexión (bind) por defecto.

Entonces, ¿Qué opciones tenemos? y ¿Por qué


funciona en el caso anterior?
Existen varias maneras de manejar el this dentro de una
clase. Pero en esta ocasión, hablaremos de tres
opciones que tenemos para hacerlo.

1ra opción: Conexión en el render()


class App extends Component {
... onIncrementClick() { ... } render() {
...
<Button
...
onIncrementClick={this.onIncrementClick.bind(this)}
>
} ...
}

La principal ventaja de esta opción es que es bastante claro


que es lo que estamos haciendo. El problema, es que
podemos afectar el rendimiento de la aplicación. La función
es reasignada cada vez que se renderiza el componente. (Ver
Gist).
2da opción: Conexión en el constructor()
class App extends Component {
constructor(props) {
super(props);

this.onIncrementClick = this.onIncrementClick.bind(this);
} onIncrementClick() { ... } render() {
...
<Button
...
onIncrementClick={this.onIncrementClick}
>
} ...
}

Usando esta opción podemos resolver los problemas de la


primera opción. Sacrificamos un poco de claridad,
y mejoramos el rendimiento de nuestra aplicación. (Ver
Gist).

Pero esta opción tiene una contra, ¿Qué pasa si en nuestra


clase estamos manejando 3, 4, 10 eventos?. ¡Correcto!, por
cada una de las funciones tendremos que declarar la
conexión en el constructor. ¿Te imaginas 10 declaraciones?

Para esto tenemos nuestra tercera opción. La utilizamos en


nuestro código anteriormente. ¿Cuál es esta opción?¿Por
qué funciona?

3ra opción: usando arrow functions de ES6


class App extends Component {
constructor(props) {
super(props);

} onIncrementClick = () => { ... } render() {


...
<Button
...
onIncrementClick={this.onIncrementClick}
>
} ...
}
Recordemos las características de las arrow functions en ES6,
una de ellas nos habla sobre this dentro de las arrow
functions. this hace referencia a lo mismo dentro y
fuera de la función. La conexión, se dice, que se hace de
manera “automática”. Esta opción: previene los problemas
de rendimiento de la primera opción, y los problemas de
repetición de la segunda opción. Actualmente es la
opción más popular. (Ver Gist)

En resumen
React tiene sus propios eventos, que cuentan con las
misma interfaz de los eventos nativos del navegador, con la
ventaja que los eventos de React tienen
un comportamiento compatible con la mayoría de los
navegadores.

Estos eventos reciben una función, o manejadores de


eventos. Lo que hacen estas funciones es definir el
comportamiento de la aplicación si se corre X o Y evento.

Algo muy común en React, es declarar los manejadores de


eventos como funciones dentro de una clase. Cuando
hacemos esto, debemos tener cuidado, ya que this no se
conecta por defecto a la clase. Para resolver esto, tenemos
tres opciones: hacer la conexión en el render(), en
el constructor(), o usar arrow functions. Cada uno tiene
sus ventajas y desventajas, depende de nosotros tomar la
decisión sobre cual usaremos.

Código fuente: GitHub


7. Ciclos
de Vida de los
Componentes de React
Los componentes clase deben pasar por varias etapas, y
cada etapa pasa por uno o varios ciclos de vida.

Los ciclos de vida son funciones especiales, que nos


permiten ejecutar funciones o declarar lógica de manera
más desmenuzada, dándonos mayor control sobre todo el
proceso de renderizado de nuestros componentes.

Los componentes son creados, montados, actualizados,


y desmontados.

Veamos cada ciclo de vida en detalle:

Los componentes son creados y actualizados


Nuestros componentes deben pasar una vez por esta etapa.
En esta, se ejecutan los ciclos de vida, desde que
se invoca el componente hasta que se muestra por
primera vez en la interfaz gráfica. En el siguiente orden:

• constructor():
este ciclo de vida se ejecuta cuando el
componente es instanciado. Acá podemos definir su
configuración inicial. Por ejemplo, configurar
el estado o crear conexiones con nuestras funciones.
constructor(props) {
super(props);

this.state = {
initialState: true,
}; this.method = this.method.bind(this);
}
• componentWillMount():
las modificaciones en este ciclo de
vida no causan actualizaciones en el componente, y se
corre justo antes de montar o renderizar el
componente. Por ejemplo, un cambio condicional en
el estado.
componentWillMount() {
let answer;
if(this.props.number % 3 === 0 && this.props.number % 5 ===
0) {
answer = 'fizzbuzz';
} else if(this.props.number % 3 === 0) {
answer = 'buzz';
} else if(this.props.number % 5 === 0) {
answer = 'fizz';
} else {
answer = this.props.number
}

this.setState({
answer: answer
});
}

• render(): este método, en esta etapa, genera la interfaz


gráfica inicial. Modificar el estado puede causar un
ciclo infinito. Por esta razón este método debe se puro.
render() {
return (
<h1>Hello world</h1>
);
}

• componentDidMount():el código que retorna nuestra función


ya ha sido renderizado en el DOM y nuestra interfaz,
hemos llegado al final de la etapa de montado. Este
método solo se ejecuta una única vez. Es perfecto para
trabajar con código asincrónico, llamados a APIs, y
código retrasado con setTimeout.
componentDidMount() {
apiCallMethod()
.then(() => {
this.setState({ success: true });
})
.catch(() => {
this.setState({ success: false });
});
}
}

Los componentes se actualizan. Bueno, no


siempre
Los componentes pueden o no actualizarse, y lo pueden
hacer más de una vez. Los cambios en el estado o en
las propiedades, son los causantes de estas
actualizaciones, generando una interfaz con los nuevos
valores. Los ciclos es esta etapa son:

• componentWillReceiveProps(nextProps):
el primer ciclo en la
etapa de actualización. Nos permite hacer cambios en el
componente basados en un cambio en las propiedades.
La razón por la que este método recibe el
parámetro nextProps, es para permitirnos validar el
cambio en las propiedades. nextProps debe ser diferente
a this.props.
componentWillReaceiveProps(nextProps) {
if(this.props.num1 !== nextProps.num1 || this.props.num2
!== nextProps.num2) {
this.setState({
sum: nextProps.num1 + nextProps.num2,
})
}
}

• shouldComponentUpdate(nextProps, nextState): nos permite


validar un cambio en el estado o en
las propiedades del componente por medio
de nextProps, this.props, nextState, y this.state y
retornar verdadero o falso para renderizar
nuevamente o no el componente, respectivamente. Por
defecto, siempre retorna true.
shouldComponentUpdate(nextProps, nextState) {
return nextProps.name !== this.props.name
}

• componentWillUpdate(nextProps, nextState):
se ejecuta
cuando shouldComponentUpdate() retorna verdadero. Se
hacen los últimos cambios antes de renderizar
nuevamente el componente.
componentWillUpdate(nextProps, nextState) {
if(this.state.age !== nextStage.age) {
this.onGrow();
}
}

• componentDidUpdate(prevProps, prevState):
este es el último
método de esta etapa. El componente se ha renderizado
con los nuevos valores. Es perfecto para interactuar
con el DOM
componentDidUpdate(prevProps, prevState) {
this.createCard();
}

Los componentes son desmontados


Está es la última fase de los componentes. Consta de
un único método que es invocado justo antes de que el
componente sea destruido o sea sacado de nuestra
interfaz.

• componentWillUnmount():
su principal funcionalidad
es limpiar nuestro componente. Por ejemplo, dejar de
escuchar eventos o cancelar peticiones HTTP
pendientes.
componentWillUnmount() {
window.removeEventListener(anyEvent, anyEventHandler());
}
Conclusión
Entender los ciclos de vida de React es muy importante.
Estos nos permiten empoderarnos de los recursos de
nuestra aplicación.

Un buen manejo de los ciclos de vida,


puede mejorar el rendimiento de nuestra aplicación
y mejorar la experiencia del usuario. Al igual que un mal
manejo, puede llevarnos a pérdida de memoria y una mala
experiencia para el usuario.

También podría gustarte