useRef
es un Hook de React que te permite referenciar un valor que no es necesario para el renderizado.
const ref = useRef(initialValue)
Referencia
useRef(initialValue)
Llama a useRef
en el nivel superior de tu componente para declarar una ref.
import { useRef } from 'react';
function MyComponent() {
const intervalRef = useRef(0);
const inputRef = useRef(null);
// ...
Mira ejemplos de cómo referenciar valores y manipulación de DOM.
Parámetros
initialValue
: El valor que quieres que tenga inicialmente la propiedadcurrent
del objeto ref. Puede ser un valor de cualquier tipo. Este argumento se ignora después del renderizado inicial.
Devuelve
useRef
devuelve un objeto con una sola propiedad:
current
: Inicialmente, se establece en elinitialValue
que has pasado. Más tarde puedes establecerlo a otra cosa. Si pasas el objeto ref a React como un atributoref
a un nodo JSX, React establecerá su propiedadcurrent
.
En los siguientes renderizados, useRef
devolverá el mismo objeto.
Advertencias
- Puedes mutar la propiedad
ref.current
. A diferencia del estado, es mutable. Sin embargo, si contiene un objeto que se utiliza para el renderizado (por ejemplo, una parte de tu estado), entonces no deberÃas mutar ese objeto. - Cuando cambias la propiedad
ref.current
, React no vuelve a renderizar tu componente. React no está al tanto de cuándo la cambias porque una ref es un objeto JavaScript plano. - No escribas ni leas
ref.current
durante el renderizado, excepto para la inicialización. Esto hace que el comportamiento de tu componente sea impredecible. - En el modo estricto, React llamará a la función de tu componente dos veces para ayudarte a encontrar impurezas accidentales. Este es un comportamiento solo de desarrollo y no afecta en producción. Esto significa que cada objeto ref se creará dos veces, y una de las versiones se descartará. Si la función de tu componente es pura (como deberÃa ser), no deberÃa afectar a la lógica de tu componente.
Uso
Referenciar un valor con una ref
Llama a useRef
en el nivel superior de tu componente para declarar una o más refs.
import { useRef } from 'react';
function Stopwatch() {
const intervalRef = useRef(0);
// ...
useRef
devuelve un objeto ref con una sola propiedad current
establecida inicialmente con el valor inicial que proporcionaste.
En los siguientes renderizados, useRef
devolverá el mismo objeto. Puedes cambiar su propiedad current
para almacenar información y leerla más tarde. Esto puede recordarte al estado, pero hay una diferencia importante.
El cambio de una ref no provoca un nuevo renderizado. Esto significa que las refs son perfectas para almacenar información que no afecta a la salida visual de tu componente. Por ejemplo, si necesita almacenar un ID de intervalo y recuperarlo más tarde, puedes ponerlo en una ref. Para actualizar el valor dentro de la ref, es necesario cambiar manualmente supropiedad current
:
function handleStartClick() {
const intervalId = setInterval(() => {
// ...
}, 1000);
intervalRef.current = intervalId;
}
Más tarde, puedes leer el ID de ese intervalo desde la ref para poder limpiar ese intervalo:
function handleStopClick() {
const intervalId = intervalRef.current;
clearInterval(intervalId);
}
Al utilizar una ref, te aseguras de que:
- Puedes almacenar información entre renderizados (a diferencia de las variables regulares, que se reinician en cada renderizado).
- Si se cambia no se desencadena un renderizado (a diferencia de las variables de estado, que desencadenan un renderizado).
- La información es local para cada copia de tu componente (a diferencia de las variables externas, que son compartidas).
El cambio de una ref no desencadena un renderizado, por lo que las refs no son apropiadas para almacenar información que se quiere mostrar en la pantalla. Utiliza el estado para eso. Lee más sobre elegir entre useRef
y useState
.
Ejemplo 1 de 2: Contador de clics
Este componente utiliza una ref para llevar la cuenta de las veces que se ha pulsado el botón. Ten en cuenta que está bien usar una ref en lugar de un estado aquà porque el recuento de clics sólo se lee y se escribe en un manejador de eventos.
import { useRef } from 'react'; export default function Counter() { let ref = useRef(0); function handleClick() { ref.current = ref.current + 1; alert('You clicked ' + ref.current + ' times!'); } return ( <button onClick={handleClick}> Click me! </button> ); }
Si muestras {ref.current}
en el JSX, el número no se actualizará al hacer clic. Esto se debe a que el establecimiento de ref.current
no desencadena un renderizado. La información que se utiliza para el renderizado debe ser estado.
Manipulación del DOM con una ref
Es particularmente común utilizar una ref para manipular el DOM. React tiene soporte incorporado para esto.
En primer lugar, declara una objeto ref con un valor inicial de null
:
import { useRef } from 'react';
function MyComponent() {
const inputRef = useRef(null);
// ...
Luego pasa tu objeto ref como el atributo ref
al JSX del nodo DOM que quieres manipular:
// ...
return <input ref={inputRef} />;
Después de que React cree el nodo DOM y lo ponga en la pantalla, React establecerá la propiedad current
de tu objeto ref a ese nodo DOM. Ahora puedes acceder al nodo DOM de <input>
y llamar a métodos como focus()
:
function handleClick() {
inputRef.current.focus();
}
React establecerá la propiedad current
a null
cuando el nodo sea eliminado de la pantalla.
Lee más sobre la manipulación del DOM con refs.
Ejemplo 1 de 4: Enfocar una entrada de texto
En este ejemplo, al hacer clic en el botón se hará foco en la entrada de texto o input:
import { useRef } from 'react'; export default function Form() { const inputRef = useRef(null); function handleClick() { inputRef.current.focus(); } return ( <> <input ref={inputRef} /> <button onClick={handleClick}> Focus the input </button> </> ); }
Evitar la recreación del contenido de las refs
React guarda el valor inicial de la ref una vez y lo ignora en los siguientes renderizados.
function Video() {
const playerRef = useRef(new VideoPlayer());
// ...
Aunque el resultado de new VideoPlayer()
sólo se utiliza para el renderizado inicial, todavÃa estás llamando a esta función en cada renderizado. Esto puede ser un desperdicio si está creando objetos costosos.
Para solucionarlo, puedes inicializar la ref de esta manera:
function Video() {
const playerRef = useRef(null);
if (playerRef.current === null) {
playerRef.current = new VideoPlayer();
}
// ...
Normalmente, no se permite escribir o leer ref.current
durante el renderizado. Sin embargo, está bien en este caso porque el resultado es siempre el mismo, y la condición sólo se ejecuta durante la inicialización por lo que es totalmente predecible.
Deep Dive
Si utilizas un comprobador de tipos y no quieres comprobar siempre la existencia de null
, puedes probar con un patrón como éste:
function Video() {
const playerRef = useRef(null);
function getPlayer() {
if (playerRef.current !== null) {
return playerRef.current;
}
const player = new VideoPlayer();
playerRef.current = player;
return player;
}
// ...
AquÃ, el propio playerRef
puede ser null
. Sin embargo, deberÃas ser capaz de convencer a tu comprobador de tipos de que no hay ningún caso en el que getPlayer()
devuelva null
. Luego usa getPlayer()
en tus manejadores de eventos.
Solución de problemas
No puedo obtener una ref a un componente personalizado
Si intentas pasar una ref
a tu propio componente de esta manera
const inputRef = useRef(null);
return <MyInput ref={inputRef} />;
Es posible que aparezca un error en la consola:
Por defecto, tus propios componentes no exponen refs a los nodos del DOM que hay dentro de ellos.
Para solucionarlo, busca el componente del que quieres obtener una ref:
export default function MyInput({ value, onChange }) {
return (
<input
value={value}
onChange={onChange}
/>
);
}
Y luego envuélvelo en forwardRef
de la siguiente forma:
import { forwardRef } from 'react';
const MyInput = forwardRef(({ value, onChange }, ref) => {
return (
<input
value={value}
onChange={onChange}
ref={ref}
/>
);
});
export default MyInput;
Luego el componente padre puede obtener una ref a él.
Más información sobre el acceso a los nodos DOM de otro componente.