DEV Community

dux
dux

Posted on • Updated on

¿Cómo rayos funciona el hook useRef en React? 🧐

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.
import React, { useRef } from 'react';
Enter fullscreen mode Exit fullscreen mode
  • Su declaración es sencilla:
const variableDeReferencia = useRef(valorInicial);
Enter fullscreen mode Exit fullscreen mode

Por ejemplo:

const inputRef = useRef();
Enter fullscreen mode Exit fullscreen mode

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

<input type="text" ref={inputRef} />
Enter fullscreen mode Exit fullscreen mode

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:
<input type="text" id="mi-input" />
Enter fullscreen mode Exit fullscreen mode
const input = document.querySelector("#mi-input");
// o también esto:
const input = document.getElementById("mi-input");
Enter fullscreen mode Exit fullscreen mode

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.

Ejemplo #2

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

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:

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:

  • En <App /> renderizamos condicionalmente el componente <Users />

  • <Users /> hace una llamada a la API JSON placeholder 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:

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


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:


img

Discussion (3)

Collapse
lukeshiru profile image
LUKESHIRU

Bien ahi avisando que los ejemplos son "de juguete", porque todos esos se pueden solucionar sin useRef (e idealmente asi debe ser). Para aquellos que quieran saber como:

  • Ejemplo #1: Pueden usar un estado y hacer log de eso:
const [value, setValue] = useState("");

// ...
<input value={value} onChange={({ currentTarget: { value } }) => setValue(value)} />
<button onClick={() => console.log(value)}>Show</button>
Enter fullscreen mode Exit fullscreen mode
  • Ejemplo #2: Usar autofocus y listo.
<input autofocus />
Enter fullscreen mode Exit fullscreen mode
  • Ejemplo #3: De nuevo podemos usar un estado para esto 😄
const [red, setRed] = useState(false);

// ...
<div className={`box ${red ? "red" : ""}`}>Hello world</div>
<button onClick={() => setRed(true)}>Change color</button>
Enter fullscreen mode Exit fullscreen mode

Saludos!

Collapse
duxtech profile image
dux Author

Excelente comentario para complementar un poco más lo ilustrado en el post @lukeshiru , es complicado encontrar casos de usos reales para este hook, y eso lo hace algo ambiguo. Saludos.

Collapse
lukeshiru profile image
LUKESHIRU

Totalmente! En general los casos de uso de este hook se limitan a superficie de contacto con otros frameworks o librerias, o incluso Web Components con APIs no estandar. Es completamente entendible que recurras a ejemplos como este para entender como funciona.