Fundamentos de React
Tags: react, javascript, beginners, webdev
Published: 2020-12-17 14:25:47

La idea sobre este post es comenzar a devolver y compartir un poco de lo que he ido aprendido a lo largo de estos años.

Cada vez que busco información la misma está, por lo general, en inglés y creo que esto genera una brecha entre los que pudimos aprender el idioma y los que todavía no han tenido la posibilidad de hacerlo.

En este post, como el título lo indica, voy a estar hablando sobre los fundamentos de **React** y voy a basarme en el workshop de **Kent C. Dodds** llamado **React Fundamentals**, que es parte de una serie llamada **Epic React**. El contenido se encuentra en su GitHub, donde, si así lo quisieras, podrías clonar el repo y seguir las instrucciones para desarrollarlo.

* [Epic React](https://epicreact.dev/)
* [React Fundamentals - Repo](https://github.com/kentcdodds/react-fundamentals)

También agradecer a **Bhanu Teja Pachipulusu**, ya que ver su post fue lo que me inspiro a hacer el mio propio pero para la comunidad hispanohablante.

* [React Fundamentals - Bhanu Teja](https://blog.bhanuteja.dev/react-fundamentals)

# ¡Comencemos! <a name="start"></a>

Índice:
* [¿Cómo se encarga **JavaScript** de renderizar un Hello World?](#javascript-basico)
* [¿Cómo **React** se encarga de renderizar un Hello World?](#react-basico)
* [Anteriormente mencioné **JSX**, ¿Qué es?](#jsx)
* [Interpolación en **JSX**](#jsx-interpolation)
* [Componentes custom](#custom-component)
* [PropTypes](#proptypes)
* [Fragments](#fragments)
* [Estilos](#estilos)
* [Formularios](#forms)
* [Refs](#refs)
* [Componentes no controlados](#uncontrolled-components)
* [Componentes controlados](#controlled-components)
* [Renderizando arrays](#render-arrays)

## ¿Cómo se encarga **JavaScript** de renderizar un Hello World? <a name="javascript-basico"></a>

Supongamos que tenemos el siguiente archivo **HTML**: 

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>
```

¿Cómo haríamos con **JavaScript** para renderizar `<div class="container">Hello World</div>` dentro de `<div id="root"></div>`?

Deberíamos utilizar la **API** que **JavaScript** nos provee para interactuar con el **DOM**, veamos cómo:

```javascript
<script type="text/javascript">
  // Obtenemos una referencia del elemento root en el DOM.
  const rootElement = document.getElementById('root');

  // Creamos el nuevo div que va a contener el texto: "Hello World" y la clase "container"
  const newElement = document.createElement('div');
  newElement.textContent = 'Hello World';
  newElement.className = 'container';

  // Insertamos el nuevo elemento creado
  rootElement.append(newElement);
</script>
```

Ejemplo en vivo: [CodeSandbox](https://codesandbox.io/s/7nrn2)

##### [Volver al índice](#start)


## ¿Cómo **React** se encarga de renderizar un Hello World? <a name="react-basico"></a>

Para comenzar de una manera rápida existe [unpkg.com](https://unpkg.com/), que nos expone **react** y **react-dom** desde una url y nos da acceso a su **API** para desarrollar. Mejoremos un poco nuestro archivo **HTML** para darle soporte para **React**.

>##### Pero te podrás preguntar, ¿Qué son **react** y **react-dom**? ¿Qué los diferencia?
>
>* **react**: _te permite crear elementos **React**, el método que más vamos a utilizar es createElement y, la verdad es que, la mayoría del tiempo lo vamos a estar usando sin saberlo, ya que vamos a estar escribiendo **JSX** que, por debajo, lo que hace es llamar a este método._
>* **react-dom**: _se encarga de renderizar el contenido en el **DOM**._


```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
  </head>
  <body>
    <div id="root"></div>
    <script src="https://unpkg.com/react@17.0.0/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@17.0.0/umd/react-dom.development.js"></script>
  </body>
</html>
```

Como dijimos previamente, de **react** vamos a estar utilizando el método `React.createElement` y de react-dom vamos a utilizar `ReactDOM.render`.

`React.createElement` crea y retorna un nuevo elemento **React** y acepta 3 parámetros:
- el tipo, que puede ser el nombre de la etiqueta **HTML** como `div` o `span`, un componente **React** (clase o función) o **Fragment**, que ya veremos más adelante.
- propiedades para el componente, como por ejemplo: _className_, _id_, _children_.
- children, como 'Hello World'. Puede haber 1 o N. Si hay más de uno, se los agrupa como un arreglo.

> **Dato**: _dentro de las propiedades podemos incluir una propiedad children, que es lo mismo que pasarlo como tercer parámetro. Debemos tener en cuenta que no tiene sentido utilizar ambas al mismo tiempo, dado que la del tercer parametro tiene mayor peso; si está existiere, sólo se mostraría esa_.

> Visualicemos:
> ```react
React.createElement('div', { children: 'props' }, 'Tercer parametro');
// OUTPUT
<div>Tercer parametro</div>
```

Obtendríamos el mismo resultado de cualquiera de las siguientes maneras:

```javascript
React.createElement('div', { className: 'container', children: 'Hello World' })
// o
React.createElement('div', { className: 'container'}, 'Hello World' })
```

`ReactDOM.render` renderiza un elemento **React** al **DOM** en el contenedor suministrado; acepta dos parámetros y uno opcional:
- Elemento a ser renderizado.
- Contenedor donde el elemento va a ser renderizado.
- Callback a ser ejecutado luego de que el componente sea renderizado o actualizado.

Se vería así:
`ReactDOM.render(elemento, contenedor[, callback])`

Luego de esta introducción a los métodos que vamos a estar utilizando, veamos cómo hacer con **React** lo mismo que hicimos previamente con **JavaScript**:

```javascript
<script type="text/javascript">
  // Obtenemos una referencia del elemento root en el DOM.
  const rootElement = document.getElementById('root')

  // Creamos el nuevo div que va a contener el texto: "Hello World" y la clase "container"
  const newElement = React.createElement('div', { className: 'container' }, 'Hello World')

  // Insertamos el nuevo elemento creado
  ReactDOM.render(newElement, rootElement)
</script>
```

Ejemplo en vivo: [CodeSandbox](https://codesandbox.io/s/yz6hu)

#### ¿Qué pasa si no queremos un solo elemento dentro del root?
No hay problema, la prop children soporta que le pasemos un arreglo de elementos:

```javascript
<script type="text/javascript">
  // Obtenemos una referencia del elemento root en el DOM.
  const rootElement = document.getElementById('root');

  // Creamos nuevos elementos react
  const helloElement = React.createElement('div', null, 'Hello');
  const worldElement = React.createElement('div', null, 'World');

  // Creamos un elemento que va a contener ambos elementos previamente creados
  const divElement = React.createElement('div', {
    className: 'container',
    children: [
     helloElement,
     " ",
     worldElement
    ]
  });

  // Insertamos el nuevo elemento creado
  ReactDOM.render(divElement, rootElement);
</script>
```

Recuerden, podemos hacerlo de cualquiera de estas dos formas:

```javascript
React.createElement('div', {
  className: 'container',
  children: [
    helloElement, 
    worldElement
  ]
});
// o
React.createElement('div', {
  className: 'container',
}, helloElement, worldElement);
``` 

Ejemplo en vivo: [CodeSandbox](https://codesandbox.io/s/n0l7l)

##### [Volver al índice](#start)


## Anteriormente mencioné **JSX**, ¿Qué es? <a name="jsx"></a>

**JSX** es una extensión de **JavaScript** creada por Facebook. A primera vista nos puede parecer que estamos mezclando **JavaScript** con **HTML**, lo que nos hace más fácil desarrollar los componentes de **React** pero, en realidad, es sólo azúcar sintáctico para la función de `React.createElement(component, props, ...children)`.

Tal como hicimos anteriormente con **React**, vamos a tener que agregar **Babel** a nuestra web para poder utilizar **JSX**, ya que no es código **JavaScript** válido por sí mismo.

Mejoremos otra vez nuestro **HTML** para poder practicar algunos conceptos:

> Podemos utilizar [Babel - Try out](https://babeljs.io/repl#?browsers=defaults%2C%20not%20ie%2011%2C%20not%20ie_mob%2011&build=&builtIns=usage&spec=false&loose=false&code_lz=MYewdgzgLgBArgSxgXhgHgCYIG4D40QAOAhmLgBICmANtSGgPRGm7rNkDqIATtRo-3wMseAFBA&debug=false&forceAllTransforms=false&shippedProposals=false&circleciRepo=&evaluate=false&fileSize=false&timeTravel=false&sourceType=module&lineWrap=true&presets=react&prettier=true&targets=&version=7.12.10&externalPlugins=) para ir viendo cómo Babel transpila nuestro código y su resultado final.

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
  </head>
  <body>
    <div id="root"></div>
    <script src="https://unpkg.com/react@17.0.0/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@17.0.0/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/@babel/standalone@7.12.4/babel.js"></script>
    <script type="text/babel">
      // Con type="text/babel" le estamos diciendo al browser que este script debe ser transpilado por Babel

      // ...nuestro código
    </script>
  </body>
</html>
```

Hay que tener en cuenta ciertas cosas a la hora de escribir **JSX**:
* Tenemos ciertas palabras reservadas en **JavaScript** que son iguales a algunos atributos **HTML**, por eso, al utilizarlos, tenemos que cambiarlos por su semejante en **JSX**. Por ejemplo, class por _className_ o for por _htmlFor_.
* Los atributos en **JSX**, a excepción de los _aria-*_, deben ser escritos en camelCase.
* Debemos cerrar todas las etiquetas. Por ejemplo, `<span></span>` o `<img />`.
* Nunca olvidar que **JSX** espera que retornemos **un solo elemento**.

Sigamos avanzando con los ejemplos anteriores para ponerlo en práctica. ¿Recuerdan el `<div class=”container”>Hello World</div>`?

Vamos a escribirlo tanto con **React.createElement** como con **JSX**:

```react
// React.createElement
const newElement = React.createElement('div', { className: 'container' }, 'Hello World');

// JSX
const newElement = <div className="container">Hello World</div>;
```

Veamos ahora cómo haríamos el ejemplo con dos children:

```react
// React.createElement
const helloElement = React.createElement('div', null, 'Hello');
const worldElement = React.createElement('div', null, 'World');
const divElement = React.createElement('div', {
  className: 'container',
}, helloElement, worldElement);

// JSX
const divElement = (
  <div className="container">
    <div>Hello</div>
    <div>World</div>
  </div>
);
```

¿No es mucho más fácil de entender e imaginar el resultado final?

Ejemplo en vivo: [CodeSandbox](https://codesandbox.io/s/xvwx1)

##### [Volver al índice](#start)


## Interpolación en **JSX** <a name="jsx-interpolation"></a>

Al **JSX** estár escrito en **JavaScript**, podemos hacer algunas cosas muy interesantes. Por ejemplo, utilizar **JavaScript** dentro del **JSX**, pero para poder hacer esto utilizaremos `{}` para envolver nuestro **JavaScript** y esto le notifica a **Babel** que acá se está interpolando **JSX** y **JavaScript**.

Veámoslo en ejemplo. Tomemos el siguiente código:
`const newElement = <div className="container">Hello World</div;`

Digamos que queremos que, tanto la clase como su children, sean dinámicos, que queramos definirlos como variables por fuera. Podríamos hacer algo así:

```react
const myClass = 'container';
const children = 'Hello world';
const newElement = <div className={myClass}>{children}</div>;
```

Y eso es todo, ¿no es simple y poderoso?

### Puntos a tener en cuenta:
* No podemos hacer declaraciones dentro de los `{}`:

```react
const newElement = (
  <div className={myClass}>
    {if (children) {
          ...code
       }
    }
   </div>
);
```

En cambio sí podemos utilizar expresiones:

```react
const newElement = (
  <div className={myClass}>
    // Ternarios
    {children
      ? `El hijo es: ${children}`
      : 'No tiene hijo'
    }
   </div>
);
```

Ejemplo en vivo: [CodeSandbox](https://codesandbox.io/s/mdypy)

### ¿Qué pasa si tenemos un objeto de props que queremos aplicar a nuestro **JSX**?

```react
const newElementProps = {
  className: 'myClass',
  children: 'Hello World',
};
```

Aplicando lo visto anteriormente, podríamos hacer:

```react
const newElement = (
  <div className={newElementProps.className}> 
    {newElementProps.children}
  </div>;
);
```

¿No es tedioso tener que estar utilizando siempre el objeto `newElementProps`, y cada una de sus keys para definir cada una de las props del elemento? Imaginemos si tenemos 30 props.

¿No te gustaría sólo decir: "okey, quiero que todas las props del objeto  `newElementProps` sean aplicadas acá"? Te tengo una buena noticia: existe la forma, ¡¡gracias **spread**!!

```react
// React.createElement
const newElement = React.createElement('div', newElementProps);

// ¿Qué pasa si por ejemplo, el elemento ya tiene una prop id?
const newElement = React.createElement('div', {id: 'my-id', ...newElementProps });

// JSX
const newElement = <div {...newElementProps} />;

// JSX y con prop id
const newElement = <div id="my-id" {...newElementProps} />;
```

### ¿Qué deberíamos tener en cuenta a la hora de usar el spread?

Hay que tener en cuenta en qué posición realizamos el _spread_ de las props. Éste sobreescribe las de igual nombre, si es realizado luego de la definición. Por ejemplo:

```react
const props = {
  className: 'myClass',
  id: 'my-id-for-spread'
};

const newElement = <div {...props } id="my-id">Hello</div>;
// El resultado en este caso sería:
// <div className="myClass" id="my-id">Hello</div>

// En cambio, si lo aplicamos de la siguiente manera:
const newElement2 = <div id="my-id" {...props }>Hello</div>;
// El resultado en este caso sería:
// <div className="myClass" id="my-id-for-spread">Hello</div>
```

Ejemplo en vivo: [CodeSandbox](https://codesandbox.io/s/dtfps)

##### [Volver al índice](#start)


## Componentes custom <a name="custom-components"></a>
Por lo general, cuando comenzamos a desarrollar una aplicación, nos damos cuenta que existen elementos comunes que vamos a estar repetiendo, sean botones, mensajes, etc.

**JSX** nos permite utilizar **JavaScript** para crear nuestros componentes. Por ejemplo, abstraer las cosas comunes en una función que retorna **JSX**, o sea, un **React Element**.

Vayamos paso a paso. Supongamos que tenemos el siguiente caso:

```react
<div className="container">
  <div className="message">Hello</span>
  <div className="message">World</span>
</div>
```

Claramente observamos que los elementos `div` son exactamente iguales, lo único que cambia es el texto que está mostrando. Entonces, ¿qué haríamos?

Abstraer ese elemento a una función:
```react
function message(text) {
  return <div className="message">{text}</div>
}
```

Ahora podríamos aplicar lo que aprendimos anteriormente en **JSX** y la interpolación:
```react
<div className="container">
  {message('Hello'})}
  {message('World'})}
</div>
```

Esto funciona perfectamente, pero podríamos mejorar un poco el código pensando en cómo funciona `React.createElement`, que utiliza la prop children para renderizar.

```react
// Destructurando las props nos da una idea rápida
// de las props que el componente está esperando
function message({ children }) {
  return <div className="message">{children}</div>
}

<div className="container">
  {message({ children: 'Hello' })}
  {message({ children: 'World' })}
</div>
```

Anteriormente dijimos que prácticamente no vamos a estar escribiendo `React.createElement` por todos lados, sino que vamos a estar utilizando **JSX**.

En los ejemplos anteriores vimos que:
```react
// React.createElement:
const newElement = React.createElement('div', { className: 'container' }, 'Hello');

// JSX:
const newElement = <div className="container">Hello</div>;
```

Entonces, podríamos suponer que, siguiendo ese ejemplo, lo que debemos hacer es lo siguiente:

```react
<div className="container">
  <message>Hello</message>
  {React.createElement(message, { children: 'World' })}
</div>
```

A primera vista parecería que está funcionando pero, cuando vamos a las _tools_ y examinamos los elementos, vemos que, en vez de estar renderizando `<div className="message">Hello</div>`, lo que está pasando es que se está renderizando `<message>Hello</message>`, que, claramente, no es lo que estamos esperando que pase.

![elements](https://dev-to-uploads.s3.amazonaws.com/i/4hn75rv8m74qvvtyi8fw.png)

Si vamos a la consola, nos vamos a encontrar:
![warning](https://dev-to-uploads.s3.amazonaws.com/i/q341qao67b3djcubwugn.png)

La razón de esto es cómo **Babel** compila nuestro código:
![babel](https://dev-to-uploads.s3.amazonaws.com/i/jx28l4l1gnxkwsip9n60.png)

Podemos observar que, cuando utilizamos `<message>`, **Babel**, en vez de compilar a `React.createElement(message)`, lo que hace es compilar a `React.createElement('message')`.

Entonces, para solventar esto, lo que debemos hacer es exactamente lo que dice el warning de la consola: _utilizar mayúsculas para nuestros componentes_.

```react
function Message({ children }) {
  return <div className="message">{children}</div>
}

<div className="container">
  <Message>Hello</Message>
  <Message>World</Message>
</div>
```

Ahora, si volvemos a ir a las _tools_ y examinar los elementos, vemos que todo se está renderizando correctamente.

Al poner nuestro componente en mayúscula, **Babel** identifica que es un componente de **React** y, en lugar de al _type_ agregarle comillas, lo pasa directamente para que el browser pueda manejar esa referencia en el scope.

Ejemplo en vivo: [CodeSandbox](https://codesandbox.io/s/f7yv3)

##### [Volver al índice](#start)


## PropTypes, ¿qué son? y ¿para qué sirven? <a name="proptypes"></a>
Hay aplicaciones en donde se utiliza [Flow](https://flow.org/) o [TypeScript](https://www.typescriptlang.org/) para verificar los tipos en **JavaScript**, pero no es una regla y **React** nos provee de **PropTypes** para verificarlos si así lo quisiéramos.

Comencemos modificando el componente custom que creamos anteriormente para que acepte un nombre y un saludo:

```react
function Message({ nombre, saludo }) {
  return (
    <div className="message">
      Hey {nombre}, {saludo}
    </div>
  );
}

<div className="container">
  <Message nombre="Denis" saludo="Como andas?" />
  <Message saludo="Como andas?" />
</div>

// OUTPUT
Hey Denis, Como andas?
Hey , Como andas?
```

Como podemos observar, no se ve bien. No sería un comportamiento esperado para un componente pero, al mismo tiempo, no nos está diciendo que está fallando o cómo deberíamos solventar este error.

Sería interesante poder hacer algo similar a lo que pasaba cuando tratábamos de renderizar un elemento **React** en minúsculas y nos decía que debíamos utilizar mayúsculas, ¿no?

Para eso, existen las PropTypes. Comencemos forzando al componente a mostrarnos un error si la prop _nombre_ no es un string:

```react
function Message({ nombre, saludo }) {
  return (
    <div className="message">
      Hey {nombre}, {saludo}
    </div>
  );
}

Message.propTypes = {
  nombre(props, propName, componentName) {
    if (typeof props[propName] !== 'string') {
      return new Error(`El componente ${componentName} necesita que la prop ${propName} sea de tipo "string" pero recibió ${typeof props[propName]}`);
    }
  }
};
```

Este objeto **propTypes** es algo que **React** va a referenciar cuando renderice el componente y va a pasar las props por las funciones que nosotros le proveamos al objeto para realizar las validaciones correspondientes.

Nótese que la función, en este caso, matchea con la prop en cuestión. Como primer parámetro va a recibir todas las props, como segúndo parámetro, el nombre de la prop en cuestión, y como tercer parámetro, el nombre del componente.

Ahora, si volvemos a inspeccionar la consola, vamos a notar que hay un warning:
![errorMessage](https://dev-to-uploads.s3.amazonaws.com/i/ajlzbsn54vl9u7ju0c1v.png)

¡Perfecto! ¡Es lo que buscabamos!

Ahora hagamos lo mismo con la prop _saludo_. Si lo pensamos un minuto, deberíamos utilizar la misma funcion. Entonces, para no repetir código, lo que vamos a hacer es crear un objeto **PropTypes** que contenga nuestras validaciones:

```react
const PropTypes = {
  string(props, propName, componentName) {
    if (typeof props[propName] !== 'string') {
      return new Error(`El componente ${componentName} necesita que la prop ${propName} sea de tipo "string" pero recibió ${typeof props[propName]}`);
    }
  }
};

Message.propTypes = {
  nombre: PropTypes.string,
  saludo: PropTypes.string
};
```

Ya tenemos nuestro componente que va a validar que las dos props que necesita para funcionar correctamente sean del tipo que nosotros definimos, y sino es así, que avise por qué está fallando y cómo solucionarlo.

Como estos casos son muy comunes, el equipo de  **React**  desarrolló y mantiene una librería llamada **prop-types** que, básicamente, funciona tal cuál nosotros lo implementamos.

Si quisíeramos implementarla, podríamos copiar el script que nos proveen y agregarlo en nuestra página junto con los demás scripts.

```html
<script src="https://unpkg.com/prop-types@15.7.2/prop-types.js"></script>
```

Luego, deberíamos remover nuestro objecto **PropTypes** y utilizar la variable global que el script de **prop-types** agregó a la página. Hay que tener encuenta que, por defecto, la librería te muestra un error si la propType no tiene un valor por defecto y no es requerida.

```react
function Message({ nombre, saludo }) {
  return (
    <div className="message">
      Hey {nombre}, {saludo}
    </div>
  );
}

// En nuestro caso ambos valores son requeridos para funcionar
Message.propTypes = {
  nombre: PropTypes.string.isRequired,
  saludo: PropTypes.string.isRequired
};
```

> PropTypes sólo funciona en ambientes de desarrollo por cuestiones de performance.

Ejemplo en vivo: [CodeSandbox](https://codesandbox.io/s/3o9o2)

##### [Volver al índice](#start)


## Fragments <a name="fragments"></a>
Prestemos atención al siguiente caso:

Nos gustaría obtener el siguiente resultado final:

![fragments](https://dev-to-uploads.s3.amazonaws.com/i/sp7uhvb4xzkk23us11vl.png)
 
Comencemos obteniendo la referencia del nodo **root** y creando los elementos que queremos insertarle:

```react
const rootElement = document.getElementById('root');
const helloElement = <div className="hello">Hello</div>;
const worldElement = <div className="world">World</div>;
```

Hasta acá perfecto pero, ¿ahora? ¿Cómo agregamos estos dos elementos?

Sabemos que, para renderizar un elemento en otro, utilizamos `ReactDom.render(element, contenedor)`. Pero, también sabemos que este método espera que le pasemos un solo elemento como argumento para renderizar en el contenedor.

Una forma de resolverlo podría ser:

```react
const newElement = (
  <div>
    <div className="hello">Hello</div>
    <div className="world">World</div>
  </div>
)
```

Pero, el resultado final, no sería el que nosotros esperamos. Estaríamos viendo:

![output-fragments](https://dev-to-uploads.s3.amazonaws.com/i/ngh8gdl0zxxsavn582l0.png)

Esto no es lo que queríamos realmente, entonces.. ¿cómo podemos resolverlo? **Si, con Fragments**.

**React Fragments** fue introducido en la version **16.2.0** y llegó a resolver exactamente este problema. Ahora somos capaces de renderizar múltiples elementos envolviéndolos en `<React.Fragment></React.Fragment>`:
 
```react
const newElement = (
  <React.Fragment>
    <div className="hello">Hello</div>
    <div className="world">World</div>
  </React.Fragment>
);
```
**React** va a ignorar `<React.Fragment>` cuando renderice el componente, por lo cuál, el resultado final sí quedaría como lo estabamos esperando.

Es realmente útil cuando la estructura del **DOM** es realmente importante. Por ejemplo, si estás utilizando **Flexbox** o **Grid** en un elemento padre y el componente hijo tiene N elementos y estos tienen que alinearse de determinada manera.

 También podemos escribirlos de la siguiente manera:
 ```react
const newElement = (
  <>
    <div className="hello">Hello</div>
    <div className="world">World</div>
  </>
);
```
 Y se comporta de la misma manera que vimos anteriormente. **Babel** compila ambos casos a `React.createElment(React.Fragment, null, ...childrens)`

Ejemplo en vivo: [CodeSandbox](https://codesandbox.io/s/oxjuo)

##### [Volver al índice](#start)


## Estilos <a name="estilos"></a>
Podemos estilar nuestros componentes principalmente de dos maneras:

* Inline css
* Regular css

Comencemos por el primero. "inline css" es la manera de agregar estilos en línea con la propiedad _style_.

En **HTML** lo haríamos de la siguiente manera:
`<div style="color: blue; font-size: 16px">Blue text</div>`

En cambio, en **React**, la prop _style_ no está esperando un string, sino que está esperando un objeto:

```react
const myStyle = {
  color: 'blue',
  fontSize: '16px'
}

<div style={myStyle}>Blue text</div>

// O podríamos escribirlo en linea
<div style={{ color: 'blue', fontSize: '16px' }}>Blue text</div>
```

Nótese que cambia la manera en la que escribimos las propiedades de css en **React**. Las debemos escribir en camelCase en lugar de kebab-cased. Podemos notar esta diferencia en el primer ejemplo dónde, en **HTML**, escribimos font-size y, en **React**, fontSize.

Es importante entender que los valores de las propiedades del objeto style sólo pueden ser _string_ o _number_, dado que espera un objeto **JavaScript** válido. Entonces, no es posible escribir cosas como `fontSize: 16px`, lo correcto es `fontSize: '16px'`.

Cuando hablamos de "regular css", hablamos de la prop _className_ que espera un string con el nombre de la o las clases que queremos aplicarle.

`<div className=”blue-text”>Blue text</div>`

Es muy común que las clases de css dependan también de las props o del estado del componente. Por ejemplo:

```react
function Text({ bold }) {
  const className = bold ? 'blue-text--bold' : 'blue-text';
  return <span className={className}>Blue text</span>
}
```

Dependiendo del valor de la prop _bold_, podríamos obtener dos resultados:

1. bold es true: `<span className="blue-text--bold">Blue text</span>`
2. bold es false: `<span className="blue-text">Blue text</span>`

Tenemos que tener en cuenta a la hora de combinar ambas maneras de estilar nuestros componentes, la **especificidad**, dado que _style_ tiene una **especificidad** mayor a _className_. ¿Qué quiero decir con esto?

Supongamos que tenemos la clase:
```css
.blue-text {
  color: blue;
  font-size: 16px;
}
```

Y vamos a aplicarla a:
```react
<span className="blue-text" style={{ fontSize: '20px' }}>
  Blue text
</span>
```

El resultado final tendrá `color: blue` pero, en vez de contener `font-size: 16px`, tendrá `font-size: 20px`.

Ejemplo en vivo: [CodeSandbox](https://codesandbox.io/s/cky4w)

##### [Volver al índice](#start)


## Formularios <a name="forms"></a>
Partamos del siguiente formulario:

```html
<form>
  <div>
    <label htmlFor="usernameId">Nombre de usuario:</label>
    <input id="usernameId" type="text" name="username" />
  </div>
  <button type="submit">Submit</button>
</form>
```

Lo que ahora necesitamos es una función para manejar el submit de este formulario:

```react
function handleSubmit() {
  console.log('Enviado');
}
```

Una vez que tenemos la función, lo que hacemos es decirle a **React** que, cuando cree este formulario, queremos que ejecute esta función cuando el evento onSubmit es ejecutado.

Actualicemos nuestro form:

```html
<form onSubmit={handleSubmit}>
  <div>
    <label htmlFor="usernameId">Nombre de usuario:</label>
    <input id="usernameId" type="text" name="username" />
  </div>
  <button type="submit">Submit</button>
</form>
```

Cuando enviamos el formulario, el navegador, por defecto, va a hacer una petición **GET** con los valores del formulario como parámetros de consulta (query params) en la URL y, lo que vamos a ver, es que la página se refresca completamente.

Para evitar este comportamiento por defecto, modificamos nuestro `handleSubmit` para preveenirlo:

```react
function handleSubmit(event) {
  event.preventDefault();
  console.log('Enviado');
}
```

Claramente, no sólo vamos a querer prevenir el evento y hacer un `console.log()`. Probablemente querramos acceder a los valores de los inputs, por ejemplo, y ésto podemos lograrlo de distintas maneras:

* `event.target` nos facilita un array con los elementos ordenados como aparecen en el form. Por ejemplo, en este caso, sólo tenemos un elemento, por lo que podríamos acceder al valor haciendo `event.target[0].value`.
* ¿Qué pasa si tenemos más de un elemento? Se va a tornar inmantenible hacerlo de la manera anterior. Dentro de `event.target`, vamos a encontrar que tiene una propiedad _elements_ donde podemos encontrar los elementos tanto por sus propiedades _id_, como por _name_. Esto nos facilita hacer `event.target.elements.usernameId.value` o  `event.target.elements.username.value`, para obtener el valor actual de nuestro input.

Ejemplo en vivo: [CodeSandbox](https://codesandbox.io/s/b5l56)

##### [Volver al índice](#start)


## Refs <a name="refs"></a>
`const myRef = useRef(initialValue);`

Existe otra manera de obtener la referencia a un elemento de **React** y es utilizando **Refs**.

Ésta devuelve un objeto mutable, cuya propiedad `.current` se inicializará con el argumento sumistrado (initialValue).

>Hay que destacar que se mantiene consistente entre los rerenders del componente y, además, modificarlo no hará que el componente se rerenderice.

Cuando asignamos nuestra ref a un elemento **React**, `.current` va a tener una referencia a ese elemento.

Entonces, si relacionamos esto con el ejemplo anterior, deducimos que podemos obtener el valor del input utilizando refs. Veamos cómo:

```react
function Form() {
  const usernameRef = React.useRef(null);

  function handleSubmit(event) {
    event.preventDefault();
    console.log(usernameRef.current.value);
  }

  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label htmlFor="usernameId">Nombre de usuario:</label>
        <input
          id="usernameId"
          name="username"
          ref={usernameRef}
          type="text”
        />
      </div>
      <button type="submit">Submit</button>
    </form>
  )
}
```

Ejemplo en vivo: [CodeSandbox](https://codesandbox.io/s/46nvm)

##### [Volver al índice](#start)


## Componentes no controlados <a name="uncontrolled-components"></a>
En nuestro ejemplo del formulario estamos dejando que el propio **DOM** maneje los datos de los formularios. En **HTML**, los elementos como `<input>`, `<textarea>` y `<select>` mantienen sus propios estados, actualizándolos de acuerdo a la interacción del usuario y podemos acceder a ellos como vimos previamente con **Refs**.

##### [Volver al índice](#start)


## Componentes controlados <a name="controlled-components"></a>
Los componentes controlados manejan su propio estado y sólo se actualizan con `setState` en los componentes de clase, y con el hook de `useState` en los componentes funcionales.

Veamos cómo transformamos nuestro componente Form en un componente controlado:

```react
function Form() {
  const [username, setUsername] = useState('');

  function handleSubmit(event) {
    event.preventDefault();
    console.log(username);
  }

  function handleChange(event) {
    setUsername(event.target.value);
  }

  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label htmlFor="usernameId">Nombre de usuario:</label>
        <input
          id="usernameId"
          name="username"
          onChange={handleChange}
          type="text”
          value={username}
        />
      </div>
      <button type="submit">Submit</button>
    </form>
  )
}
```

Ahora nosotros tenemos **control total** sobre el `input`, y el valor mostrado, será el que está siendo almacenado en `username` pasándoselo a la prop _value_. Para esto estamos utilizando el evento `onChange`, que nos permite capturar el evento cada vez que una tecla es oprimida dentro del `input` y actualizar el valor del `input` utilizando el método `setUsername` que definimos previamente.

Tener el valor del `input` en el estado del componente, nos da la flexibilidad de que si ahora queremos compartir este valor con otros elementos de la UI, podemos hacerlo. Por ejemplo, un popup o también podemos reiniciarlo desde otros manejadores de eventos.

Juguemos un poco con el `handleChange` para que sea un poco más útil y, por ejemplo, setee un error cuando el usuario intenta ingresar un carácter no válido:

```react
function Form() {
  const [username, setUsername] = useState('');
  const [error, setError] = useState('');

  function handleSubmit(event) {
    event.preventDefault();
    console.log(username);
  }

function handleChange(event) {
  const { target: { value } } = event;
  // solo queremos que el usuario ingrese letras, de lo contrario mostramos un mensaje de error
  const esValido = /^[a-zA-Z]+$/g.test(value);
  setError(esValido ? null : 'El nombre de usuario solo permite letras')
  setUsername(value);
}

  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label htmlFor="usernameId">Nombre de usuario:</label>
        <input
          id="usernameId"
          name="username"
          onChange={handleChange}
          type="text"
          value={username}
        />
       {error ? <div role="alert">{error}</div> : null}
      </div>
      <button type="submit">Submit</button>
    </form>
  )
}
```

Ejemplo en vivo: [CodeSandbox](https://codesandbox.io/s/jqrh6)

##### [Volver al índice](#start)


## Renderizando arrays <a name="render-arrays"></a>
Cuando queremos renderizar una lista de elementos, **React** requiere que le pasemos como prop una `key` única para cada elemento. Esto le permite identificarlo y saber qué tiene que hacer con él en cada render.

```react
function ListaDeUsuarios({ usuarios }) {
  const listaDeUsuarios = usuarios.map(usuario => <li>{usuario}</li>); 

  return <ol>listaDeUsuarios</ol>;
}

const usuarios = ['Juan', 'Pedro', 'Sofia', 'Valentina'];

ReactDom.render(
  <ListaDeUsuarios usuarios={usuarios} />,
  document.getElementById('root')
);
```

Cuando este código sea ejecutado, vamos a recibir una alerta de que cada ítem de la lista debe tener una `key` asignada. Usualmente vamos a utilizar los _IDs_ de nuestros datos. Como última instancia, podemos utilizar el _índice_, pero vale aclarar que, por defecto, es lo que hace **React** cuando no encuentra una y ésto no es una buena práctica.

Las `keys` ayudan a **React** a identificar qué ítems han cambiado, son agregados o son eliminados. Deben ser únicas solo entre hermanos, pero no necesariamente deben ser únicas globalmente.

```react
const listaUsuarios = [
  { id: "juan1", nombre: "Juan" },
  { id: "pedro2", nombre: "Pedro" },
  { id: "sofia3", nombre: "Sofia" },
  { id: "valentina4", nombre: "Valentina" }
];

function ListaUsuarios() {
  const [usuarios, setUsuarios] = React.useState(listaUsuarios);

  function eliminarUsuario(usuario) {
    setUsuarios(
      usuarios.filter(
        (usuariosActuales) => usuariosActuales.id !== usuario.id
      )
    );
  }

  function resetLista() {
    setUsuarios(listaUsuarios);
  }

  return (
    <div>
      <ul style={{ listStyle: "none" }}>
        {usuarios.map((usuario) => (
          <li>
            <button onClick={() => eliminarUsuario(usuario)}>Eliminar</button>
            <label htmlFor={usuario.id}>{usuario.nombre}</label>
            <input id={usuario.id} defaultValue={usuario.nombre} />
          </li>
        ))}
      </ul>
      <button onClick={() => resetLista()}>Reset</button>
    </div>
  );
}
```

Como primera instancia podemos observar que la consola nos está arrojando un error:
![key-error](https://dev-to-uploads.s3.amazonaws.com/i/y6cukrn9312l74g2gqy0.png)

Esto ocurre por lo que dijimos antes: _**React** espera que le pasamos una key única para cada elemento de una lista._

Además, si jugamos un poco con el código anterior removiendo usuarios en distinto orden, podemos observar cómo los valores por defecto de un elemento dejan de coincidir. Esto ocurre porque, al no estar proporcionándole una key única al elemento, **React** no sabe a ciencia cierta qué elemento fue modificado y esto puede derivar en comportamientos inesperados en el estado de un elemento no controlado.

Con tan sólo agregarle una key única a cada elemento de la lista, solventamos el error de la consola y, a la vez, podemos observar como todo funciona de manera correcta:

```react
{usuarios.map((usuario) => (
  <li key={usuario.id}>
    <button onClick={() => eliminarUsuario(usuario)}>Eliminar</button>
    <label htmlFor={usuario.id}>{usuario.nombre}</label>
    <input id={usuario.id} value={usuario.nombre} />
  </li>
))}
```

Ejemplo en vivo: [CodeSandbox](https://codesandbox.io/s/xh588)

##### [Volver al índice](#start)

### Gracias por su tiempo. Espero que les sea de utilidad y puedan aplicarlo en el futuro.
### Saludos!

> Links y referencias:
* [Epic React](https://epicreact.dev/)
* [React Fundamentals - Repo](https://github.com/kentcdodds/react-fundamentals)
* [React Fundamentals - Bhanu Teja](https://blog.bhanuteja.dev/react-fundamentals)
* [MDN Web Doc ](https://developer.mozilla.org/es/)
* [Documentación de React](https://es.reactjs.org/docs/getting-started.html)
* [React sin JSX](https://es.reactjs.org/docs/react-without-jsx.html)
* [React con JSX](https://es.reactjs.org/docs/introducing-jsx.html)
* [JSX en profundidad](https://es.reactjs.org/docs/jsx-in-depth.html)
* [Componentes custom](https://es.reactjs.org/docs/components-and-props.html)
* [PropTypes](https://es.reactjs.org/docs/typechecking-with-proptypes.html)
* [Fragments](https://es.reactjs.org/docs/fragments.html)
* [Inline css](https://es.reactjs.org/docs/dom-elements.html#style)
* [Regular css](https://es.reactjs.org/docs/faq-styling.html)
* [Formularios](https://es.reactjs.org/docs/forms.html#gatsby-focus-wrapper)
* [Refs](https://es.reactjs.org/docs/hooks-reference.html#useref)
* [Componentes no controlados](https://es.reactjs.org/docs/uncontrolled-components.html)
* [Componentes controlados](https://es.reactjs.org/docs/forms.html#controlled-components)
* [Renderizando arrays](https://es.reactjs.org/docs/lists-and-keys.html)