¿Cómo rayos funciona el hook useRef en React? 🧐
Tags: react, javascript, webdev, spanish
Published: 2021-09-20 15:17:29


## Intro
En pleno 2021 la gran mayoría de los desarrollos hechos en react usan **hooks**, los primeros, más básicos y los que prácticamente usaras en el 100% de tus desarrollos sin lugar a dudas son `useState` y `useEffect`; pero muchos dev olvidan que hay otros hooks bastante interesantes, menos conocidos, pero igual de importantes para aplicarlos a casos de uso específicos, uno de ellos obviamente es `useRef`.

Tratemos de comprender las bases de este hook, como funciona, y sobre todo lo más importante a mi criterio: cuando usarlo.

## **Sintaxis**
* Se lo debe importar como cualquier otro hook.
```js
import React, { useRef } from 'react';
```
* Su declaración es sencilla:
```js
const variableDeReferencia = useRef(valorInicial);
```
Por ejemplo:
```js
const inputRef = useRef();
```

> La constante `inputRef` almacena una referencia al DOM que no tiene valor inicial.

Para poder enlazar nuestra referencia, por ejemplo, a un input, se usa la propiedad `ref`

```html
<input type="text" ref={inputRef} />
```

> Ahora nuestra variable `inputRef` tiene una referencia directa al input, gracias a la propiedad `ref`.

Ahora bien, si imprimimos por consola el contenido de la variable `inputRef` veremos que nos regresa un objeto con la propiedad `current` y dentro de ella la **referencia** al input, dicha referencia tiene en su interior todas las propiedades que pueden ser usadas en un input de tipo text, como por ejemplo: `className`, `value`, `id`, `name`, `placeholder`, entre otras.

En este punto ya podemos manipular de manera directa dicho input.

## **`useRef()` casos de uso**
Este hook puede usarse en 2 casos específicos:
* **Acceder al DOM de manera directa**
Cuando necesitamos acceder a un elemento HTML del DOM, en vanilla js haríamos algo como esto:

```html
<input type="text" id="mi-input" />
```

```js
const input = document.querySelector("#mi-input");
// o también esto:
const input = document.getElementById("mi-input");
```

Este código es correcto pero cuando de proyectos grandes se trata esta sintaxis será muy complicada de mantener, por ellos y por muchos motivos más existen librerías como react que nos ayudan a manipular el DOM de una manera un poco más abstracta. Por ello existe el hook `useState` que permite crear variables de estado para poder usar el Virtual DOM de react.

Ahora bien, `useRef` accede a elementos del DOM de manera directa, sin aprovechar las bondades que nos da react, entonces, ¿por que quisiéramos hacer algo así? ¿No tiene mucho sentido verdad? Por ahora quédate con este pequeño concepto, con los ejemplos podrás comprender mejor.

### **Ejemplo #1**
Después de esta extensa pero necesaria intro, veremos un poco de código, enlazaremos un input a una referencia e imprimimos el valor del input por consola.

{% stackblitz react-2gegju %}

### **Ejemplo #2**
Al tener un formulario, podemos darle `focus` automatico al primer input cuando la página se renderiza por primera vez:

{% stackblitz react-nthwba %}

> Puedes probar recargando la página, siempre el primer input tendrá el foco por defecto.

### **Ejemplo #3**
Podemos añadir una clase CSS a un elemento del DOM apretando un botón:

{% stackblitz react-dnxyxr %}

**NOTA:** Considere estos primeros ejemplos como ejemplos de papel o de juguete, no se debería usar el hook de esta manera, solo son ejemplos para ilustrar y comprender cómo funciona `useRef`.

* **Crear una variable mutable persistente entre renders**
Este punto es el caso de uso más realista para usar `useRef`, los ejemplos anteriores podrían ser resueltos de otra manera sin necesidad de importar y usar `useRef`, ahora veremos ejemplos donde su uso es necesario.

### **Ejemplo #4**
Al hacer una llamada una API es posible que intentemos renderizar componentes condicionalmente, por ejemplo:

{% stackblitz react-fdm2s4 %}

- En `<App />` renderizamos condicionalmente el componente `<Users />`

- `<Users />` hace una llamada a la API [JSON placeholder](https://jsonplaceholder.typicode.com/users) para obtener 10 usuarios de prueba y pintarlos en pantalla cuando le damos al botón `Mostrar / Ocultar`

- Solo para el ejemplo simulamos que la respuesta de la API será de 4 segundos (lo que es una barbaridad de tiempo)

- Imaginemos que le damos click al botón, empieza a correr los 4 segundos establecidos, pero antes de que concluya y podemos ver los usuarios en pantalla, le volvemos a dar al botón,el programa seguirá funcionando pero nos aparecerá un horrible error en la consola:

**Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.**

En cristiano este error mas o menos nos dice que intentamos actualizar el estado de un componente desmontado, y no da una pista: usar la función de limpieza que el hook `useEffect`

Ahora bien, podemos resolver esto usando un `useRef` para mantener la referencia del componente y solo realizar actualizaciones de estado cuando este se encuentre montado en la aplicación.

La solución se la puede ver a continuación:

{% stackblitz react-fdx2wv %}

Intentaremos explicar un poco:
- Creamos una variable de referencia `isMountedRef` que empieza como `true`, esta variable representará al componente `<Users />` cuando esté montado.

- Ahora en el `useEffect` usamos un `return` para **MUTAR**
 el objeto y cambiar el valor a `false`, osea, componente `<Users />` cuando esté desmontado.

- Ahora con un if, solo haremos la petición con `getUsers` cuando `isMountedRef` sea `true`, dicho en otras palabras, sólo cuando el componente esté montado.

De esta manera puedes hacer peticiones a API's un poco más seguras y confiables para evitar problemas con el servidor cuando estemos en producción.

## **Referencias**
{% youtube D2ElJVzriCk%}
{% youtube 4K4yaFGcoFE%}

* https://acortar.link/JHlfEK

## **Conclusiones**
* `useRef` es un hook que permite la manipulación directa de elementos del DOM.
* `useRef` no usa el virtual DOM de react.
* Para enlazar `useRef` a un elemento HTML, dicho elemento debe tener la propiedad `ref` con el valor de la variable de referencia.
* `useRef` siempre regresa un objeto mutable con una única propiedad `current`.
* Puedes usar un `useRef` para hacer peticiones a API's de una manera más controlada, y no siempre dependiendo del servidor en producción.

---


Quiza puede ser de tu interés:

{% link https://dev.to/duxtech/3-metodos-muy-utiles-para-objetos-en-javascript-1lk8 %}
{% link https://dev.to/duxtech/react-usestate-para-dummies-analogia-ccm %}
{% link https://dev.to/duxtech/7-editores-de-codigo-en-la-nube-para-frontends-3343 %}
{% link https://dev.to/duxtech/10-trucos-y-optimizaciones-de-codigo-con-javascript-para-2021-3759 %}

--- 

![img](https://media.giphy.com/media/110IlProGBQgs8/giphy.gif?cid=ecf05e47peevju0t7c3kwyoyi7593pbvm6c7prriy5eecfju&rid=giphy.gif&ct=g)