React 101 ⚛️

🔰 Que es React


Una forma ligera, rápida y moderna de ejecutar código.


React es una librería JavaScript para simplificar el desarrollo de interfaces visuales. Los desarrolladores pueden crear grandes aplicaciones web que utilizan datos que pueden cambiar a lo largo del tiempo sin recargar la página entera.


  • Es comúnmente confundido como herramienta, framework o lenguaje.
  • Es la View en la arquitectura MVC.
  • Uno de los aspectos mas importantes es el echo de poder crear componentes, los cuales son piezas re utilizables de HTML.

Desarrollada en Facebook y publicada en forma de open source en 2013. Alguna de las aplicaciones más conocidas que utilizan esta tecnología son:

  • Facebook
  • Instagram
  • Whatsapp Web
  • Tesla
  • Atlassian
  • Airbnb
  • Netflix
  • Reddit
  • Dropbox

💯 Pros / Cons


Pros 💚

  • Eficiencia del desarrollador
  • Performance
  • Componentes reutilizables
  • Soporte Comunidad
  • Developer Tools
  • Open Source
  • Sin sesgo de opinión

Cons 🔴

  • Curva de aprendizaje
  • SEO
  • No es un framework

UX vs DX

Comúnmente durante años en la industria hemos hablado y centrado todos nuestros esfuerzos en la experiencia de usuario (UX).

Desde hace un par de décadas, los nuevos productos del ecosistema JavaScript también hacen hincapié en hacernos la vida a los desarrolladores más sencilla, la llamada developer experience (DX).

Con DX de alguna forma podamos hacer más, con menos, lo que se traduce en llegar más lejos, con más calidad en menos tiempo.

DOM

Cuando consumimos contenido web, este está representado por HTML en forma de árbol a esto lo llamamos DOM (Document Object Model).

DOMvsVDOM

¿Porqué React es tan rápido?

Cada vez que queremos cambiar algo en un punto determinado de la web, se recorre el DOM y se modifican aquellas ramas al completo que están relacionadas con el nodo donde ha habido el cambio.


React utiliza VDOM (Virtual DOM) el cual es un concepto de programación donde tenemos una representación del DOM alojada de forma virtual en el navegador.


virtualdom

Ecosistema React

React no es únicamente para desarrollar webs, actualmente tener conocimientos en React nos permite ir mucho más allá.

react-ecosystem

Ecosistema JavaScript

React se mantiene en 2020 como una de las tecnologías JavaScript más utilizadas y positivamente valoradas.

js-ecosystem

🛠️ Instalación y requisitos


Requisitos

Formas de utilizar React

Online Sandboxes

CDN

Podemos importar la librería React directamente desde la CDN a nuestro proyecto HTML existente.

<body>
  <script
    crossorigin
    src="https://unpkg.com/react@17/umd/react.development.js"
  ></script>
  <script
    crossorigin
    src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"
  ></script>
</body>
class App extends React.Component {
  //...
}

Create React App

Facebook tiene una herramienta con la cual crear nuevos proyectos React a través de una template que se va actualizando con las nuevas versiones y las configuraciones más comunes, dicha herramienta la podéis encontrar en Create React App


Para utilizarla, en un Terminal:

npx create-react-app my-react-app

create-react-app

💪 JSX: JavaScript + XML


Si has mirado código anteriormente de React, habrás visto código que parece HTML pero realmente no lo es, en realidad utilizamos JSX el cual viene de JavaScript XML.


Si conoces HTML las diferencias son pocas por lo que la curva de aprendizaje no es pronunciada.

const myJSX = <h1 className="my-css-class">Hello, React!</h1>;

Utilizar JSX no es obligatorio pero si altamente recomendado, React por detrás esta generando algo como esto:

const myJSX = React.createElement(
  'h1',
  { className: 'my-css-class' },
  'Hello, React!'
);

Algunas diferencias

Realmente JSX está mas cerca de JavaScript que de HTML, pero hay algunas diferencias a tener en cuenta.

  • className se utiliza en vez de class para los nombres de clase en CSS ya que class es una palabra reservada en JS.
  • Las propiedades en JSX son camelCase, por ejemplo onclick es onClick
  • Las tags deben auto cerrarse <img />

Se puede utilizar JavaScript dentro del JSX.

const year = new Date().getFullYear();
const heading = <h1>Welcome Marty, you're in year {year}</h1>;

🚂 Componentes


Un componente es un modulo independiente el cual puede contener, lógica, estado y vista. Prácticamente todo en React está hecho a base de componentes, los hay de dos tipos class components o function components.

import React, { Component } from 'react';

class App extends Component {
  render() {
    return (
      <div className="App">
        <h1>Hello, React!</h1>
      </div>
    );
  }
}

export default App;
import React from 'react';

const App = () => (
  <div className="App">
    <h1>Hello, React!</h1>
  </div>
);

export default App;

Actualmente lo mas común es encontrar function components.

Estructura de componentes

Los componentes como ya hemos visto son piezas atómicas, estas piezas se hacen públicas al resto de nuestra aplicación por medio de la keyword export.

En React podemos combinar diferentes piezas atómicas para crear entidades más grandes como moléculas y seguir combinándolas entre si para crear la estructura que se adecue a nuestras necesidades.

import React from 'react';

import Header from '../components/Header';
import Body from '../components/Body';
import Footer from '../components/Footer';

const Home = () => {
  return (
    <div>
      <Header />
      <Body />
      <Footer />
    </div>
  );
};

export default Home;

Diferencias entre componentes

A parte de los ya mencionados tipos de componentes, diferenciamos los componentes según la complejidad de los mismos, en este caso a grandes rasgos también tenemos dos tipos.


  • Componentes presentacionales: Son componentes sin o con poca lógica, sin estado propio, puramente dedicados a mostrar UI.
  • Componentes Contenedor: Componentes que no suelen ser atómicos, contienen una combinación de otros componentes mas pequeños, tienen lógica, estado propio, llamadas a servicios, etc.

No hay una diferencia en la sintaxis en como utilizar un componente u otro, es algo meramente teórico.

🎉 Props


Dado que los componentes están muy relacionados entre si y podemos dividir el código a niveles atómicos, necesitamos alguna forma de poder pasar los datos entre los componentes, para esto hacemos uso de las props que no dejan de ser propiedades/atributos del componente.

import React from 'react';

import Header from '../components/Header';
import Body from '../components/Body';
import Footer from '../components/Footer';

const Home = () => {
  const onScrollHandler = () => console.log('User is scrolling');

  return (
    <div>
      <Header title="Cool Webpage" />
      <Body onScroll={onScrollHandler} />
      <Footer year={2021} />
    </div>
  );
};

export default Home;

Declarar props en un componente

Las props que tenga un componente pueden venir definidas por una librería de terceros que estemos utilizando en nuestro proyecto, por el propio React o en el caso de ser un componente que hemos creado nosotros podemos definir las props que necesitemos.

import React from 'react';

const Header = props => {
  return <header>{props.title}</header>;
};

Todos los componentes de React, contienen un objeto props del cual saldrán las propiedades que envíemos desde los componentes padre.

En las propiedades podemos enviar todo tipo de datos, cualquier primitive de JS como strings o numbers, arrays, functions o incluso componentes enteros.

"Alternativas" a las props

Una de las alternativas mas utilizadas a las props es el uso del Context que veremos en slides posteriores pero también podemos enviar el contenido de un tag como propiedad.

import React from 'react';

import Header from '../components/Header';

const Home = () => {
  return (
    <div>
      <Header>Cool Webpage</Header>
    </div>
  );
};

export default Header;
import React from 'react';

const Header = props => {
  return <header>{props.children}</header>;
};

children es una propiedad especial que contiene todo lo que este entre los tags del componente.

🌀 Estado


En React tenemos, a grandes rasgos, dos tipos de estado:

  • Global: Es el estado propio de la aplicación en su conjunto, se suele manejar de forma centralizada.
  • Por componente: Los propios componentes pueden tener un estado propio que solo incumbe a ellos mismos o sus nodos hijos.

Para manejar el estado de los componentes React nos provee de dos funciones, useState y useEffect. Estas funciones se conocen como hooks.

Hay librerías como Redux o Recoil que están 100% enfocadas al manejo del estado de forma global.

Render y Re-render

Antes de hablar sobre el estado en detalle, repasemos algunos conceptos. Hablamos de render cuando un componente se pinta en pantalla y de re-render cuando este se actualiza, pasa por el core de React y se vuelve a pintar.

La regla general es: "Todos los componentes en React hacen re-render solo si cambian sus props o el estado".

import React from 'react';

const Counter = () => {
  const count = 0;

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => (count += 1)}>Click me!</button>
      <button onClick={() => (count = 0)}>Reset</button>
    </div>
  );
};

export default Counter;

¿Porque no funciona?

You clicked 0 times

useState

Para dotar a un componente de estado, tan solo debemos utilizar el hook useState dentro del componente.

import React, { useState } from 'react';

const Counter = () => {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me!</button>
      <button onClick={() => setCount(0)}>Reset</button>
    </div>
  );
};

export default Counter;

La utilización de useState consta de varios apartados:

  • El nombre de la variable de estado que queramos
  • La función con la que se le asignarán nuevos valores
  • Un valor inicial

You clicked 0 times

useState

Es una mala practica no dividir el estado, ya que podría darse el caso de modificar el objeto y perder datos por el camino.

import React, { useState } from 'react';

const Counter = () => {
  const [count, setCount] = useState({ value: 0, isFresh: true });

  return (
    <div className="react-component">
      <p>You clicked {count.value} times</p>
      <p>I'm {count.isFresh ? 'fresh' : 'not fresh'}</p>
      <button
        onClick={() => setCount({ value: count.value + 1, isFresh: false })}
      >
        Click me!
      </button>
      <button onClick={() => setCount({ value: 0, isFresh: true })}>
        Reset
      </button>
    </div>
  );
};

export default Counter;

You clicked 0 times

I'm fresh

useState

El estado, por regla general debe ser lo mas atómico posible.

import React, { useState } from 'react';

const Counter = () => {
  const [count, setCount] = useState(0);
  const [isFresh, setIsFresh] = useState(true);

  return (
    <div className="react-component">
      <p>You clicked {count} times</p>
      <p>I'm {isFresh ? 'fresh' : 'not fresh'}</p>
      <button
        onClick={() => {
          setCount(count + 1);
          setIsFresh(false);
        }}
      >
        Click me!
      </button>
      <button
        onClick={() => {
          setCount(0);
          setIsFresh(true);
        }}
      >
        Reset
      </button>
    </div>
  );
};

export default Counter;

useEffect

Este hook nos permite controlar el ciclo de vida del componente y reaccionar a los distintos cambios que van sucediendo en el mismo.

import React, { useEffect, useState } from 'react';

const Counter = () => {
  const [count, setCount] = useState(0);
  const [welcomeMsg, setWelcomeMsg] = useState('');

  useEffect(() => {
    setWelcomeMsg('Welcome to the counter app');
  }, []);

  const onClickHandler = () => {
    setWelcomeMsg('Do you like it?');
    setCount(count + 1);
  };

  return (
    <div className="react-component">
      <p>{welcomeMsg}</p>
      <p>You clicked {count} times</p>
      <button onClick={onClickHandler}>Click me!</button>
      <button onClick={() => setCount(0)}>Reset</button>
    </div>
  );
};

export default Counter;

Welcome to the counter app

You clicked 0 times

Ciclos de vida

Con useEffect podemos reaccionar en diferentes momentos del ciclo de vida del componente, las diferentes opciones son:

  • El componente se renderiza por primera vez
  • El componente efectúa un re-render
  • La aplicación efectúa un re-render
  • El componente se destruye del DOM

lifecycle-events

Ciclos de vida

useEffect(() => {
  console.log('I get executed when characters variable changes');
}, [characters]);

useEffect(() => {
  console.log('I get executed when characters and/or jobs variables changes');
}, [characters, jobs]);

useEffect(() => {
  console.log('I get executed with the first render');
}, []);

useEffect(() => {
  console.log('I get executed every render');
});

useEffect(() => {
  console.log('I get executed with the first render');
  return () => {
    console.log("I get executed when I've been destroyed");
  };
}, []);

Podemos tener tantos useEffect como necesitemos en un mismo componente

useContext

Un problema muy común en aplicaciones de tamaño medio-grande es tener que pasar propiedades de estado a muchos niveles de profundidad entre componentes. Para solucionar este problema, podemos hacer uso del hook useContext.

Con el contexto crearemos un contenedor que englobará el componente padre y todos los componentes hijos, de esta forma podremos acceder a los datos del contexto desde cualquier nivel de profundidad sin tener que pasarlo proactivamente como prop.

useContext

import React, { createContext, useContext, useState } from 'react';

const CounterContext = createContext();

const Display = () => {
  const value = useContext(CounterContext);
  return <p>You clicked {value} times</p>;
};

const Counter = () => {
  const [count, setCount] = useState(0);

  return (
    <div className="react-component">
      <CounterContext.Provider value={count}>
        <Display />
        <button onClick={() => setCount(count + 1)}>Click me!</button>
        <button onClick={() => setCount(0)}>Reset</button>
      </CounterContext.Provider>
    </div>
  );
};

export default Counter;

You clicked 0 times

useContext

Se pueden tener tantos contextos como se necesiten, es una buena práctica separarlos por conceptos o necesidades, pero también podemos imitar el patrón de contexto global.

🎖️ Estilos


En React hay multitud de formas de cambiar los estilos de nuestra aplicación. Entre las mas comunes:

  • CSS / SASS
  • CSS / SASS Modules
  • CSS in JS (in-line, styled-components, emotion)
  • Frameworks (Bootstrap, TailwindCSS)

CSS / SASS

Igual que se hace en HTML podemos utilizar archivos .css o .scss para dotar de estilo nuestros componentes.

La estructura general de archivos de un componente debería ser muy similar a la siguiente:

|- components
|-- MyComponent
|--- MyComponent.js
|--- MyComponent.css
|--- index.js

Dentro de MyComponent.js debemos incluir el archivo de estilos.

import React from 'react';

import './MyComponent.css';

const MyComponent = () => {
  return <h1 className="my-component-style">MyComponent</h1>;
};

export default MyComponent;

Recordad que class es una keyword reservada, debemos utilizar className para indicar que clase CSS queremos utilizar.

CSS / SASS - Pros y Cons

Pros

  • CSS es un standard que lleva en la industria muchos años, los archivos CSS pueden ser re aprovechados en otras aplicaciones fuera del ecosistema React.

Cons

  • Por mucho que definamos los estilos a nivel de componente, al final React los emplaza en el tag <head> del HTML resultante, por lo que hay que tener en mente que si repetimos nombres de clases, colisionarán entre ellas.

CSS / SASS Modules

Para solventar el problema que mencionábamos anteriormente, se crearon los Modules. Si hemos creado nuestro proyecto React con create-react-app es tan sencillo como hacer la siguiente estructura de archivos:

|- components
|-- MyComponent
|--- MyComponent.js
|--- MyComponent.module.css
|--- index.js

Dentro del archivo MyComponent.module.css definiremos las clases CSS de la misma forma, pero al aplicarlas en el componente lo haremos de la siguiente forma:

import React from 'react';

import classes from './MyComponent.module.css';

const MyComponent = () => {
  return <div className={classes.MyClass} />;
};

export default MyComponent;

Con esto lo que conseguimos es que el builder inserte un hash al nombre de la clase CSS, de tal forma que no se repitan los nombres.

Modules - Pros y Cons

Pros

  • No hay problemas con el solapamiento de nombres.
  • Se sigue utilizando CSS.

CSS in JS

Como sugiere el nombre, CSS in JS es un patrón para utilizar los atributos que hay en el CSS directamente en un objeto JS, por esta razón las propiedades serán camelCase.

<div style={{ borderBottom: '1px solid black' }} />

Con esto nos aseguramos que no hay problemas de solapar nombres de clases CSS ya que asignamos individualmente los estilos a un elemento.

const MyComponent = () => {
  const style = {
    backgroundColor: 'red',
    color: 'white',
    font: 'inherit',
    border: '1px solid blue',
    padding: '8px',
    cursor: 'pointer',
    margin: '0 5px auto'
  };

  style.backgroundColor = 'green';

  return (
    <div>
      <p style={style}>We have the same style</p>
      <p style={style}>We have the same style</p>
    </div>
  );
};

CSS in JS - Pros y Cons

Pros

  • Es mas amigable para un perfil mas experto en JS que en CSS
  • No hay problemas con el solapamiento de nombres
  • Es mas sencillo manejar cambios de estilo a través de variables JS

Cons

  • No es un standard que se pueda utilizar fácilmente fuera del ecosistema React.
  • Se debe recargar la aplicación mientras se codifica.
  • Se incrementa notablemente el tamaño del JS a empaquetar.

📡 Comunicación


Hasta ahora hemos visto puramente la parte de la vista, pero en algún momento si nuestra web es mas una aplicación web que una web necesitaremos interactuar con datos exteriores.

Las dos formas mas comunes de comunicarse con el exterior en React son:

  • Usar la propia API de Javascript fetch.
  • Usar una librería de terceros como axios.

Comunicarse con el exterior en React esta considerado como un side-effect y a estas alturas ya conocemos el sitio perfecto donde hacer uso de los efectos.

fetch

import React, { useEffect, useState } from 'react';

const PostFetch = () => {
  const [posts, setPosts] = useState([]);

  useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/posts')
      .then(result => result.json())
      .then(result => {
        setPosts(result);
      });
  }, []);

  return (
    <div>
      {posts && posts.length ? (
        posts.map(post => (
          <div>
            <h4>{post.title}</h4>
            <p>{post.body}</p>
          </div>
        ))
      ) : (
        <div>Loading posts...</div>
      )}
    </div>
  );
};

export default PostFetch;

axios

import React, { useEffect, useState } from 'react';
import axios from 'axios';

const PostFetch = () => {
  const [posts, setPosts] = useState([]);

  useEffect(() => {
    axios
      .get('https://jsonplaceholder.typicode.com/posts')
      .then(result => {
        setPosts(result);
      })
      .catch(error => console.log(error));
  }, []);

  return (
    <div>
      {posts && posts.length ? (
        posts.map(post => (
          <div>
            <h4>{post.title}</h4>
            <p>{post.body}</p>
          </div>
        ))
      ) : (
        <div>Loading posts...</div>
      )}
    </div>
  );
};

export default PostFetch;

fetch vs axios

fetch

  • Fetch viene integrado en el propio JS, no es necesario instalar ninguna librería de terceros.
  • Fetch es una API moderna por lo que navegadores mas antiguos no la tienen integrada.

axios

  • Axios ofrece mayor compatibilidad entre navegadores
  • Permite mucha configuración a nivel de headers, respuestas por defecto, etc.
  • Ofrece interceptores para hacer acciones globales en las request y responses.
  • Conversion automática de las respuestas JSON.
  • Protección contra ataques XSRF (Cross-site request forgery).

📦 Librerías de terceros


A continuación se listan las dependencias que solemos utilizar, ordenadas por orden de recomendación.

UI

Styling

📦 Librerías de terceros


Gestión del estado

Llamadas HTTP/HTTPS

Tratado de fechas, tiempos, etc.

Types

Testing

🔎 Depuración


El código generado por React es perfectamente legible para aquellas personas que ya conozcan HTML y JS, por lo que depurar el código con las herramientas habituales del navegador no será un problema.

Para depurar más en detalle componentes, el estado, que está viajando por el contexto y demás particularidades de React, existen las React Developer Tools un plugin oficial para Chrome y Firefox el cual nos permitirá hacer un análisis en todo momento del estado de nuestros componentes, estado, contexto, etc.

react-developer-tools

React Developer Tools

El plugin se integrara con nuestro navegador y en las herramientas del desarrollador aparecerán dos nuevas opciones.

react-developer-tools-in-action

📦 Paquete React


Estructura de un proyecto React

Los proyectos React cuando están montados sobre un proyecto propio más allá del uso por CDNs, suelen venir acompañados de algunos conceptos adicionales.

  • package manager: Normalmente utilizamos npm o yarn, este software nos ayuda a manejar las dependencias al instalar librerias de terceros. En el archivo package.json en la raiz de nuestro proyecto encontraremos una lista de dependencias y sus versiones.

  • module bundler: Lo más común es utilizar webpack, el cual ya viene por defecto al usar Create React App, aun que también hay alternativas como Parcel. El module bundler genera un paquete con las dependencias, así como con los diferentes modulos JS que tenemos en nuestra aplicación para generar los archivos que finalmente subiremos a Internet. En ese proceso de construcción se le pueden indicar diferentes reglas a la hora de que version de JS queremos "compilar" u otros cambios.

Estructura de carpetas

Todo el código que se desarrolle estará alojado en la carpeta src, la cual está dividida de la siguiente forma.

assets

Cualquier contenido estático, como fuentes e imágenes que no está pensado que cambien.

components

Los elementos de pantalla que sean suisceptibles de repetirse deberán de abstraerse y crearse en forma de componente en esta carpeta con el fin de ser reutilizados.

context

Aquellos contextos que necesitemos para nuestra aplicación estarán alojados en esta carpeta.

hooks

Igual que con las piezas de UI, si tenemos lógica que se repite habitualmente debemos valorar abstraerlo en un hook.

pages

Cualquier ruta que decidamos que sea accesible mediante navegación debe ir en esta carpeta de cara a tener una visión rápida y clara de cuantas/cuales pantallas tiene el proyecto.

React 101 ⚛️

formulas

Daniel Asta Gutiérrez