A tu propio ritmo

Explora nuestra extensa colección de cursos diseñados para ayudarte a dominar varios temas y habilidades. Ya seas un principiante o un aprendiz avanzado, aquí hay algo para todos.

Bootcamp

Aprende en vivo

Únete a nosotros en nuestros talleres gratuitos, webinars y otros eventos para aprender más sobre nuestros programas y comenzar tu camino para convertirte en desarrollador.

Próximos eventos en vivo

Catálogo de contenidos

Para los geeks autodidactas, este es nuestro extenso catálogo de contenido con todos los materiales y tutoriales que hemos desarrollado hasta el día de hoy.

Tiene sentido comenzar a aprender leyendo y viendo videos sobre los fundamentos y cómo funcionan las cosas.

Buscar en lecciones


← Regresar a lecciones

El Hook useRef en React: Gestionando Referencias DOM y Valores Persistentes

¿Qué es useRef?
Casos de Uso Clave para useRef

El hook useRef es una herramienta poderosa en la API de hooks de React que proporciona una forma de crear una referencia mutable que persiste a través de los renderizados. A diferencia de las variables de estado, cambiar el valor de una referencia no desencadena un nuevo renderizado, lo que lo hace ideal para ciertos casos de uso que exploraremos en esta lección.

¿Qué es useRef?

El hook useRef devuelve un objeto mutable con una propiedad .current que se inicializa con el argumento proporcionado. Este objeto persiste durante toda la vida útil del componente.

1const refContainer = useRef(initialValue);

El objeto devuelto por useRef tiene dos características importantes:

  1. Es mutable: Puedes modificar su propiedad .current
  2. Es persistente: Mantiene la misma referencia a través de los renderizados

Casos de Uso Clave para useRef

1. Acceder a Elementos DOM

Uno de los usos más comunes de useRef es acceder y manipular elementos DOM directamente:

1import React, { useRef, useEffect } from 'react'; 2 3function AutoFocusInput() { 4 // Crear una referencia 5 const inputRef = useRef(null); 6 7 // Usar la referencia en useEffect 8 useEffect(() => { 9 // Enfocar el elemento input cuando el componente se monta 10 inputRef.current.focus(); 11 }, []); 12 13 return <input ref={inputRef} type="text" />; 14}

En este ejemplo:

  1. Creamos una referencia con useRef(null)
  2. La adjuntamos a un elemento input con el atributo ref
  3. Accedemos al nodo DOM real a través de inputRef.current
  4. Llamamos al método nativo focus() en el elemento input

2. Almacenar Valores Persistentes

Otro uso poderoso de useRef es mantener un valor que persiste a través de los renderizados sin causar nuevos renderizados cuando cambia:

1import React, { useRef, useEffect, useState } from 'react'; 2 3function IntervalCounter() { 4 const [count, setCount] = useState(0); 5 6 // Almacenar el ID del intervalo en una referencia para que persista entre renderizados 7 const intervalIdRef = useRef(null); 8 9 useEffect(() => { 10 // Configurar el intervalo 11 intervalIdRef.current = setInterval(() => { 12 setCount(prevCount => prevCount + 1); 13 }, 1000); 14 15 // Limpiar el intervalo 16 return () => { 17 clearInterval(intervalIdRef.current); 18 }; 19 }, []); // Array de dependencias vacío significa que se ejecuta una vez al montar 20 21 return <div>Contador: {count}</div>; 22}

Aquí, usamos una referencia para almacenar el ID del intervalo para poder limpiarlo cuando el componente se desmonte. Usar una referencia es mejor que una variable de estado porque:

  • No necesitamos re-renderizar cuando cambia el ID del intervalo
  • No necesitamos el ID del intervalo en el JSX, solo en la función de limpieza

3. Rastrear Valores Anteriores

Puedes usar referencias para rastrear valores anteriores de props o estado:

1import React, { useRef, useEffect, useState } from 'react'; 2 3function TrackChanges({ value }) { 4 const prevValueRef = useRef(); 5 const [hasChanged, setHasChanged] = useState(false); 6 7 useEffect(() => { 8 // Comprobar si el valor ha cambiado desde el último renderizado 9 if (prevValueRef.current !== undefined && prevValueRef.current !== value) { 10 setHasChanged(true); 11 } 12 13 // Actualizar la referencia al valor actual para el próximo renderizado 14 prevValueRef.current = value; 15 }, [value]); 16 17 return ( 18 <div> 19 <p>Valor actual: {value}</p> 20 {hasChanged && <p>¡El valor ha cambiado!</p>} 21 </div> 22 ); 23}

Este patrón es útil cuando necesitas comparar valores actuales y anteriores para realizar efectos secundarios.

useRef vs. useState

Es importante entender cuándo usar useRef versus useState:

CaracterísticauseRefuseState
Desencadena re-renderizado cuando se actualizaNo
Persiste entre renderizados
Patrón de accesoref.current[state, setState]
Mejor paraReferencias DOM, almacenar valores sin re-renderizadosEstado de UI que necesita ser mostrado

Usa useRef cuando:

  • Necesitas acceder a elementos DOM directamente
  • Necesitas almacenar un valor que no debería desencadenar un re-renderizado cuando cambia
  • Necesitas mantener un seguimiento de valores mutables que no afectan directamente a la UI

Usa useState cuando:

  • El valor necesita mostrarse en la UI
  • Los cambios en el valor deberían causar que el componente se vuelva a renderizar
  • Necesitas que React rastree los cambios en el valor

Patrones Comunes y Mejores Prácticas

Manejo de Inicialización

1// Inicialización perezosa 2const videoRef = useRef(null); 3 4// Con valor inicial 5const countRef = useRef(0);

Acceso a Nodos DOM

1// Acceso DOM básico 2const imageRef = useRef(null); 3 4// Más adelante en el código: 5if (imageRef.current) { 6 const dimensions = { 7 width: imageRef.current.clientWidth, 8 height: imageRef.current.clientHeight 9 }; 10}

Evitar Errores Comunes

  1. No uses referencias para valores que deberían actualizar la UI:
1// Uso incorrecto - La UI no se actualizará cuando count cambie 2const countRef = useRef(0); 3const handleClick = () => { 4 countRef.current += 1; 5 // ¡No ocurre re-renderizado! 6}; 7 8// Uso correcto 9const [count, setCount] = useState(0); 10const handleClick = () => { 11 setCount(count + 1); 12 // El componente se volverá a renderizar 13};
  1. Siempre verifica si la referencia está adjunta antes de usarla:
1// Buena práctica 2const inputRef = useRef(null); 3 4const focusInput = () => { 5 // Comprobar si la referencia está adjunta 6 if (inputRef.current) { 7 inputRef.current.focus(); 8 } 9};

Ejemplos Prácticos

1. Controles de Reproductor de Video

1import React, { useRef, useState } from 'react'; 2 3function VideoPlayer() { 4 const videoRef = useRef(null); 5 const [isPlaying, setIsPlaying] = useState(false); 6 7 const handlePlayPause = () => { 8 if (isPlaying) { 9 videoRef.current.pause(); 10 } else { 11 videoRef.current.play(); 12 } 13 setIsPlaying(!isPlaying); 14 }; 15 16 return ( 17 <div> 18 <video 19 ref={videoRef} 20 src="https://example.com/video.mp4" 21 /> 22 <button onClick={handlePlayPause}> 23 {isPlaying ? 'Pausar' : 'Reproducir'} 24 </button> 25 </div> 26 ); 27}

2. Rastreador de Posición de Desplazamiento

1import React, { useRef, useEffect, useState } from 'react'; 2 3function ScrollTracker() { 4 const containerRef = useRef(null); 5 const [scrollPercentage, setScrollPercentage] = useState(0); 6 7 useEffect(() => { 8 const container = containerRef.current; 9 10 const handleScroll = () => { 11 if (container) { 12 const scrollTop = container.scrollTop; 13 const scrollHeight = container.scrollHeight - container.clientHeight; 14 const percentage = (scrollTop / scrollHeight) * 100; 15 setScrollPercentage(Math.round(percentage)); 16 } 17 }; 18 19 container.addEventListener('scroll', handleScroll); 20 return () => { 21 container.removeEventListener('scroll', handleScroll); 22 }; 23 }, []); 24 25 return ( 26 <div> 27 <div 28 ref={containerRef} 29 style={{ 30 height: '300px', 31 overflow: 'auto', 32 border: '1px solid #ccc' 33 }} 34 > 35 {/* Contenido aquí */} 36 <div style={{ height: '1000px' }}> 37 Desplázate hacia abajo para ver el cambio de porcentaje 38 </div> 39 </div> 40 <p>Posición de desplazamiento: {scrollPercentage}%</p> 41 </div> 42 ); 43}

Cuándo No Usar useRef

Aunque useRef es poderoso, no siempre es la herramienta adecuada:

  1. No lo uses para eludir el flujo de datos de React

    • El flujo de datos unidireccional de React es una característica, no una limitación
    • Usar referencias para gestionar lo que debería ser estado puede llevar a problemas difíciles de depurar
  2. No lo uses para valores que afectan al renderizado

    • Si un valor debe desencadenar un re-renderizado cuando cambia, usa estado en su lugar
  3. No abuses del código imperativo

    • React es declarativo por diseño
    • Solo usa manipulación imperativa del DOM cuando no hay una alternativa declarativa

Patrones Avanzados de useRef

Referencias de Devolución de Llamada

Para una asignación de referencia más dinámica, puedes usar una devolución de llamada en lugar del atributo ref:

1function MeasureExample() { 2 const [height, setHeight] = useState(0); 3 4 const measuredRef = useCallback(node => { 5 if (node !== null) { 6 setHeight(node.getBoundingClientRect().height); 7 } 8 }, []); 9 10 return ( 11 <> 12 <h1 ref={measuredRef}>Hola, mundo</h1> 13 <p>El encabezado anterior tiene {Math.round(height)}px de altura</p> 14 </> 15 ); 16}

Reenvío de Referencias

Al crear abstracciones de componentes, puedes reenviar referencias a elementos internos:

1const FancyButton = React.forwardRef((props, ref) => ( 2 <button ref={ref} className="fancy-button" {...props}> 3 {props.children} 4 </button> 5)); 6 7// Uso 8function App() { 9 const buttonRef = useRef(null); 10 11 const handleClick = () => { 12 buttonRef.current.focus(); 13 }; 14 15 return ( 16 <> 17 <FancyButton ref={buttonRef}>¡Haz clic en mí!</FancyButton> 18 <button onClick={handleClick}>Enfocar el botón elegante</button> 19 </> 20 ); 21}

Conclusión

El hook useRef es una herramienta versátil en el arsenal de hooks de React. Proporciona una forma de:

  • Acceder a elementos DOM directamente cuando sea necesario
  • Almacenar valores mutables que persisten a través de renderizados
  • Llevar un seguimiento de información sin desencadenar re-renderizados

Al comprender cuándo y cómo usar useRef, puedes construir componentes React más eficientes y resolver problemas que serían difíciles con solo el estado. Recuerda que aunque el código imperativo tiene su lugar, React es fundamentalmente una biblioteca declarativa, así que usa useRef juiciosamente y preferiblemente para casos donde no existe una solución declarativa o sería excesivamente compleja.