📋 Tabla de contenidos
-
useState– El fundamento del estado -
useEffect– Efectos secundarios y ciclo de vida -
useContext– Compartir estado sin props -
useReducer– Lógica de Estado Compleja y predecible -
useRef– Referencias, Almacenamiento y Escape -
useMemoyuseCallback– Optimizando el Rendimiento - Custom Hooks – Creando Lógica Reutilizable
- Errores Comunes y Soluciones
¿Qué es y para qué sirve?
useRef es un hook versátil con dos casos de uso principales que, aunque parezcan diferentes, se basan en el mismo principio: proporcionar un objeto mutable (.current) que persiste durante todo el ciclo de vida del componente sin causar re-renderizados cuando cambia.
- Acceder a elementos del DOM: Es la "salida de emergencia" para interactuar directamente con un elemento del DOM, por ejemplo, para manejar el foco, medir su tamaño o integrar librerías de terceros (como D3.js).
- Guardar "variables de instancia": Te permite mantener un valor mutable que no necesita disparar una nueva renderización. Es como tener una variable de instancia en un componente de clase. Perfecto para guardar IDs de timers, contadores internos, o cualquier valor que necesites que sobreviva entre renders.
Sintaxis y características clave
const miRef = useRef(valorInicial);
-
useRefdevuelve un objeto con una única propiedad:current. -
miRef.currentse inicializa convalorInicial. - Puedes cambiar
miRef.currentdirectamente:miRef.current = nuevoValor. - Importante: Cambiar
miRef.currentNO dispara un re-renderizado.
Ejemplo práctico detallado: input con foco y contador de renders
Este ejemplo muestra ambos usos de useRef: uno para el DOM y otro para una variable persistente.
import React, { useState, useEffect, useRef } from 'react';
function FocusCounter() {
const [inputValue, setInputValue] = useState('');
// Caso de uso 1: Referencia al DOM
const inputRef = useRef(null);
// Caso de uso 2: Variable persistente
const renderCount = useRef(0);
useEffect(() => {
// Se ejecuta después de cada render
renderCount.current = renderCount.current + 1;
});
const handleFocus = () => {
// Accedemos al elemento del DOM directamente
inputRef.current.focus();
};
return (
<div>
<h3>Ejemplo de useRef</h3>
<input
ref={inputRef} // Conectamos la ref al elemento input
type="text"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
placeholder="Escribe algo..."
/>
<button onClick={handleFocus}>Poner Foco en el Input</button>
<p>El valor del input es: "{inputValue}"</p>
<p>Este componente se ha renderizado {renderCount.current} veces.</p>
<p>(Nota: el contador de renders no causa re-renders por sí mismo)</p>
</div>
);
}
En este ejemplo:
-
inputRefnos da acceso directo al<input>, permitiéndonos llamar a.focus(). -
renderCountlleva la cuenta de las renderizaciones. Si usáramosuseStatepara esto, cada actualización del contador causaría otro render, creando un bucle infinito. ConuseRef, podemos actualizar el valor sin efectos secundarios.
✅ Buenas practicas y patrones comunes
- Cuándo usar
useRefvsuseState:- Usa
useStatesi el cambio en el valor debe ser visible en la UI. - Usa
useRefsi necesitas que un valor persista entre renders pero no quieres que su cambio dispare una nueva renderización.
- Usa
-
Guardar el valor previo de props o estado: Un patrón muy útil es combinar
useRefyuseEffectpara "recordar" un valor del render anterior.
function Componente({ valor }) { const valorPrevioRef = useRef(); useEffect(() => { valorPrevioRef.current = valor; }, [valor]); // Se actualiza después de que el render se completa const valorPrevio = valorPrevioRef.current; // ... } Manejo de Timers:
useRefes ideal para guardar el ID desetIntervalosetTimeoutpara poder limpiarlo después.
🚨 Errores comunes y cómo evitarlos
-
Error: Acceder a
ref.currentdemasiado pronto.
// MAL ❌ function MiComponente() { const miRef = useRef(null); // Aquí, durante el primer render, miRef.current es `null` // porque el DOM aún no existe. Esto dará un error. miRef.current.focus(); return <input ref={miRef} />; }- Solución: Accede a la ref dentro de un
useEffect(que se ejecuta después del renderizado) o en manejadores de eventos (que se ejecutan por interacción del usuario).
// BIEN ✅ useEffect(() => { // Para el primer render, esto se ejecuta después de que el input existe. miRef.current.focus(); }, []); // Array vacío para que solo se ejecute una vez - Solución: Accede a la ref dentro de un
-
Error: Mostrar el valor de una ref en la UI y esperar que se actualice.
- Solución: Si necesitas que un cambio se refleje en el render, ese valor debe estar en el estado (
useState). Recuerda:useRefno notifica a React cuando cambia.
- Solución: Si necesitas que un cambio se refleje en el render, ese valor debe estar en el estado (
🚀 Retos prácticos
- Reproductor de Video: Crea un componente que muestre un video (
<video>). UsauseRefpara obtener una referencia al elemento y añade botones para "Play", "Pause" y "Stop". - Cronómetro Preciso: Haz un cronómetro que use
setInterval. Guarda el ID del intervalo en una ref para poder detenerlo y reiniciarlo correctamente. - Scroll a un Elemento: Crea una lista larga de elementos. Añade botones al principio que, al hacer clic, hagan scroll automáticamente a un elemento específico en medio de la lista (pista:
element.scrollIntoView()).
Top comments (0)