React JS ❤️ Javascript
Un repaso a algunas de las principales características de Javascript que React JS usa habitualmente
Siempre que me preguntan por qué me gusta tanto React uno de los motivos que doy es que cuando trabajamos con esta librería por el camino reforzamos y ampliamos nuestros conocimientos de Javascript: no existen funciones especiales (como por ejemplo sucede en Angular) para realizar tareas como pintar una lista de elementos o llamar a una API sino que todo es nativo. Esto quiere decir que si algún día ReactJS pierde su puesto como la librería más popular para desarrollar frontend, nuestro trabajo no habrá caído en balde pues habremos aprendido por el camino numerosos conceptos de Javascript.
En este artículo me he propuesto recoger algunas de las características y funciones de Javascript que se usan de forma intensiva cuando desarrollamos con React. Así sí estás comenzando tendrás una guía para saber qué necesitas saber sí o sí de Javascript para sentirte cómo con React.
¡Comencemos!
El operador && para pintar elementos de forma condicional
Los operadores &&
y ||
funcionan de una forma especial en Javascript pues se comportan como cortocircuitos. Esto quiere decir que su resultado no es siempre un booleano como sucede en otros lenguajes, sino que lo que obtendremos será uno de los elementos que está operando.
Concretamente el operador &&
tiene dos características:
- Se evalúa de izquierda a derecha.
- Si el primer operando evalúa a
false
el segundo operador no se evalúa.
console.log("Cat" && "Dog"); // 'Dog'
console.log(false && "Dog"); // false
Este operador se usa a menudo en React para pintar componentes de forma condicional. Imagina que quieres pintar un componente únicamente cuando se cumple una condición. Gracias al operador &&
este compotamiento es muy fácil de implementar, y lo mejor de todo es que es Javascript puro:
function Bar() { const condition = false; return ( <div> {/* Este elemento no se renderizará */} {condition && <Foo />} </div> );}
La función map para pintar listas de elementos
Otra función de Javascript que se usa recurrentemente es el método Array.prototype.map
que nos permite iterar sobre una lista de elementos y aplicar a cada uno de ellos una operación individual.
const arr = [1, 2, 3];const doubled = arr.map(n => n * 2); // [2, 4, 6]
Este método resulta especialmente útil cuando tenemos que pintar listas de elementos en React, ya que podemos emplearlo dentro del JSX de nuestro componente para iterar la lista y devolver cada elemento envuelto en el componente que queramos:
const products = ['iPhone', 'iPad', 'Apple Watch'];function Products() { return ( <ul> {products.map(product => <li key={`product--${product}`}> {product}</li>)} </ul> );}
Por cierto. Quizás te estés preguntando por qué empleamos el atributo key
en las listas de elementos similares al ejemplo anterior. A continuación te dejo un enlace a un artículo que publiqué para que sepas el motivo:
Las arrow functions
Si te has fijado, en el ejemplo anterior al método map
le estamos pasando una función expresada como “arrow function”. Esta sintaxis más corta resulta muy útil cuando la empleamos dentro de JSX, ya que nos permite expresar de una forma mucho más reducida la iteración sobre los elementos (además de que al no usar un par de llaves extra el código queda más legible):
const products = ['iPhone', 'iPad', 'Apple Watch'];function Products() { return ( <ul> {products.map(function(product) {
return (<li key={`product--${product}`}>{product}</li>);
})} </ul>);}
Además, durante la época en que todavía se definían componentes empleando clases, las “arrow functions” nos permitían ahorrarnos algún que otro susto con la variable this
(a la vez que nos ahorrábamos tener que “bindear” this
en cada método que fuera a ser usado como “event listener”):
// Sin arrow functionclass AwesomeComponent extends React.Component{
constructor( props ){
super( props );
this.onClick = this.onClick.bind(this);
} onClick(event){
// ...
} render(){
return (
<button type="button"
onClick={this.onClick}>
Click
</button>
);
}
}// Con arrow functionclass AwesomeComponent extends React.Component{ onClick = (event) => {
// ...
} render(){
return (
<button type="button"
onClick={this.onClick}>
Click
</button>
);
}
}
Si te interesa puedes leer más sobre este “problema” en el siguiente artículo:
Desestructuración de objetos
Otra de las características que Javascript nos ofrece y que recurrentemente trabajamos con ella en React es la desestructuración de objetos la cual nos permite asignar directamente a variables sus propiedades:
const person = {id: 1, name: 'Gerardo'};const {id, name, telephone = 'default telephone'} = person;console.log(id); // 1console.log(telephone); // 'default telephone'
La desestructuración es habitual cuando trabajamos con las propiedades de los componentes:
function Button({onClick, text}) {
...
}
Por supuesto esta técnica también podemos aplicarla sobre los arrays:
const lunch = ['🍝', '🥩', '🍎', '☕'];const [firstCourse] = lunch;console.log(firstCourse); // '🍝'
Algo que seguramente os suene pues es la forma en que habitualmente trabajamos con el hook useState
de React:
const [count, setCount] = useState(0);
Módulos de ES
Otra de las características que Javascript nos proporciona son los módulos, gracias a la sintaxis import-export
y que nos permite “traernos” funcionalidad declarada en otros archivos para usarla dentro del nuestro.
A estas alturas seguro que no te sorprende encontrarte con esta línea:
import React, {useState} from 'react';
Además, desde hace tiempo Javascript también soporta la importación dinámica de modulos, algo que React aprovecha para permitirnos traernos componentes de forma asíncrona y así reducir el tamaño del bundle principal. Para ello basta con emplear la instrucción lazy
para envolver la importación:
const FooComponent = React.lazy(() => import('./foo'))
Y emplear el componente Suspense
para mostrar un mensaje de cargando mientras el módulo FooComponent
es recuperado de forma asíncrona:
import {Suspense} from 'react';function Bar() {
return (
<Suspense fallback="Cargando...">
<FooComponent />
</Suspense>
);
}
🧙🏼♂️ Truco
Recuerda que si quieres trabajar con imports absolutos en tu aplicación basta con que crees en la raíz del proyecto un archivo jsconfig.json
con el siguiente contenido:
{ "compilerOptions": { "baseUrl": "src" }}
Lo cual te permitirá pasar de importar así:
import {HOME_PATH} from '../../../config/router/paths';
a importar así:
import {HOME_PATH} from 'config/router/paths'
Mucho más cómodo, ¿verdad?
Las comillas invertidas
Otra característica que en su momento incorporó ES6 y que resulta de gran utilidad cuando trabajamos con React son las comillas invertidas.
Gracias a ellas concatenar cadenas de texto y variables pasa a escribirse de una forma mucho más legible:
const name = 'Gerardo';
const surname = 'Fernández';
const telephone = '123 123 123';// "Old syntax"const userInfo = 'User info: ' + name + ' ' + surname + ' ' + telephone;// "New syntax"const userInfo = `User info: ${name} ${surname} ${telephone}`;
Esta sintaxis es habitual encontrárnosla en el JSX de nuestros componentes, pues gracias a ella podemos escribir sentencias como la siguiente:
function CounterView({counter}) {
return (<div>{`Valor del contador: ${counter}`}</div>);
}
¡Creo que la mejora es evidente!
Además, las comillas invertidas presentan otra serie de ventajas que resumí en el siguiente artículo para que puedas comprobar todo su potencial:
Chaining operator
Una de las incorporaciones más recientes que hemos recibido en Javascript es el “chaining operator” el cual nos permite acceder a las propiedades de los objetos de forma segura, sin preocuparnos de si por el camino nos encontraremos con un undefined
que provoque un fallo:
const person = {
name: 'Gerardo',
email: 'mail@mail.com'
}console.log(person.currentJob.title);// Uncaught TypeError: Cannot read property 'title' of undefined
Gracias al “chaining operator” podemos acceder a propiedades que no estamos seguros de si existen y él se encargará de devolvernos undefined
en vez de lanzar un error:
const jobTitle = person?.currentJob?.title; // undefined
Esto en React resulta muy útil si por ejemplo estamos recuperando objetos de una API cuyas propiedades no siempre se encuentran listadas, ayudándonos a prevenir posibles fallos.
Promesas y fetch
Finalmente en una recopilación de utilidades de Javascript que se emplean en React no podían faltar ni las promesas ni por supuesto la función fetch
para realizar llamadas a API’s externas:
import React, {useEffect, useState} from 'react';function MyComponent() { const [users, setUsers] = useState(null); useEffect(async function() { const response = await fetch('https://reqres.in/api/users'); const json = await response.json(); setUsers(json.data); }); if (!users) { return <div>Todavía no hay usuarios</div>; } return ( <ul> {users.map(user => <li key={`user--${user.id}`}>{user.first_name}</li>)} </ul> );}
Nuevamente React exprimiendo Javascript al máximo para implementar funcionalidad empleando las capacidades del lenguaje.
Conclusiones
Como has podido ver con todos los ejemplos que he mencionado, React al final tan sólo es una librería situada encima de Javascript para ayudarnos a desarrollar mucho más rápido nuestras aplicaciones pero en todo momento estamos recurriendo a las características del lenguaje para implementar nuestra funcionalidad.
Para mí esto es lo que realmente diferencia a React de otras librerías: sentir que vas de la mano del lenguaje y que todo lo que hoy aprendas seguro que te servirá para el futuro aunque nuestra librería favorita desaparezca.
¿Quieres recibir más artículos como este?
Si te ha gustado este artículo te animo a que te suscribas a la newsletter que envío cada domingo con publicaciones similares a esta y más contenido recomendado: 👇👇👇
Apóyame en Patreon
🧡🧡🧡 Gracias a: Joseba, Óscar, Alex, Jorge y Carolina.