useRef è un Hook React che ti permette di referenziare un valore non necessario per la renderizzazione.
const ref = useRef(initialValue)Reference
useRef(initialValue)
Chiama useRef al top level del tuo componente per dichiarare un ref.
import { useRef } from 'react';
function MyComponent() {
const intervalRef = useRef(0);
const inputRef = useRef(null);
// ...Parameters
initialValue: Il valore con cui vuoi inizializzare la proprietàcurrentdell’oggetto ref. Può essere un valore di qualsiasi tipo. Questo argomento viene ignorato dopo la renderizzazione iniziale.
Returns
useRef restituisce un oggetto con una singola proprietà:
current: Inizialmente è impostato al valoreinitialValueche hai passato. Puoi impostarlo su qualcos’altro in seguito. Se passi l’oggetto ref a React come attributorefdi un nodo JSX, React imposterà la sua proprietàcurrent.
Nelle renderizzazioni successive, useRef restituirà lo stesso oggetto.
Caveats
- Puoi mutare la proprietà
ref.current. A differenza dello state, è mutabile. Tuttavia, se contiene un oggetto usato per la renderizzazione (ad esempio, una porzione del tuo state), non dovresti mutare quell’oggetto. - Quando cambi la proprietà
ref.current, React non ri-renderizza il tuo componente. React non è a conoscenza di quando la modifichi perché un ref è un normale oggetto JavaScript. - Non scrivere né leggere
ref.currentdurante la renderizzazione, tranne per l’inizializzazione. Questo rende imprevedibile il comportamento del tuo componente. - In Strict Mode, React chiamerà la funzione del tuo componente due volte per aiutarti a trovare impurità accidentali. Questo è un comportamento solo in development e non influisce sulla production. Ogni oggetto ref verrà creato due volte, ma una delle versioni verrà scartata. Se la funzione del tuo componente è pura (come dovrebbe essere), non dovrebbe influire sul comportamento.
Usage
Referenziare un valore con un ref
Chiama useRef al top level del tuo componente per dichiarare uno o più ref.
import { useRef } from 'react';
function Stopwatch() {
const intervalRef = useRef(0);
// ...useRef restituisce un oggetto ref con una singola proprietà current inizialmente impostata al valore iniziale che hai fornito.
Nelle renderizzazioni successive, useRef restituirà lo stesso oggetto. Puoi cambiare la sua proprietà current per conservare informazioni e leggerle in seguito. Potrebbe ricordarti lo state, ma c’è una differenza importante.
Modificare un ref non avvia una ri-renderizzazione. Questo significa che i ref sono perfetti per conservare informazioni che non influenzano l’output visivo del tuo componente. Ad esempio, se devi conservare un ID di intervallo e recuperarlo in seguito, puoi metterlo in un ref. Per aggiornare il valore all’interno del ref, devi modificare manualmente la sua proprietà current:
function handleStartClick() {
const intervalId = setInterval(() => {
// ...
}, 1000);
intervalRef.current = intervalId;
}In seguito, puoi leggere quell’ID di intervallo dal ref per poter cancellare l’intervallo:
function handleStopClick() {
const intervalId = intervalRef.current;
clearInterval(intervalId);
}Usando un ref, ti assicuri che:
- Puoi conservare informazioni tra le ri-renderizzazioni (a differenza delle variabili normali, che si azzerano a ogni renderizzazione).
- Modificarlo non avvia una ri-renderizzazione (a differenza delle variabili di state, che avviano una ri-renderizzazione).
- Le informazioni sono locali a ogni copia del tuo componente (a differenza delle variabili esterne, che sono condivise).
Modificare un ref non avvia una ri-renderizzazione, quindi i ref non sono appropriati per conservare informazioni che vuoi mostrare sullo schermo. Usa lo state per quello. Leggi di più su scegliere tra useRef e useState.
Esempio 1 di 2: Contatore di click
Questo componente usa un ref per tenere traccia di quante volte è stato cliccato il pulsante. Nota che va bene usare un ref invece dello state qui perché il conteggio dei click viene letto e scritto solo in un gestore di eventi.
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> ); }
Se mostri {ref.current} nel JSX, il numero non si aggiornerà al click. Questo perché impostare ref.current non avvia una ri-renderizzazione. Le informazioni usate per la renderizzazione dovrebbero essere state.
Manipolare il DOM con un ref
È particolarmente comune usare un ref per manipolare il DOM. React ha supporto integrato per questo.
Per prima cosa, dichiara un oggetto ref con un valore iniziale di null:
import { useRef } from 'react';
function MyComponent() {
const inputRef = useRef(null);
// ...Poi passa il tuo oggetto ref come attributo ref al JSX del nodo DOM che vuoi manipolare:
// ...
return <input ref={inputRef} />;Dopo che React crea il nodo DOM e lo mette sullo schermo, React imposterà la proprietà current del tuo oggetto ref su quel nodo DOM. Ora puoi accedere al nodo DOM dell’<input> e chiamare metodi come focus():
function handleClick() {
inputRef.current.focus();
}React reimposterà la proprietà current su null quando il nodo viene rimosso dallo schermo.
Leggi di più su manipolare il DOM con i ref.
Esempio 1 di 4: Mettere a fuoco un input di testo
In questo esempio, cliccare il pulsante metterà a fuoco l’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> </> ); }
Evitare di ricreare il contenuto del ref
React salva il valore iniziale del ref una volta e lo ignora nelle renderizzazioni successive.
function Video() {
const playerRef = useRef(new VideoPlayer());
// ...Sebbene il risultato di new VideoPlayer() venga usato solo per la renderizzazione iniziale, stai comunque chiamando questa funzione a ogni renderizzazione. Questo può essere inefficiente se crea oggetti costosi.
Per risolvere, puoi inizializzare il ref così:
function Video() {
const playerRef = useRef(null);
if (playerRef.current === null) {
playerRef.current = new VideoPlayer();
}
// ...Normalmente, scrivere o leggere ref.current durante la renderizzazione non è consentito. Tuttavia, va bene in questo caso perché il risultato è sempre lo stesso, e la condizione viene eseguita solo durante l’inizializzazione, quindi è completamente prevedibile.
Approfondimento
Se usi un type checker e non vuoi controllare sempre null, puoi provare un pattern come questo:
function Video() {
const playerRef = useRef(null);
function getPlayer() {
if (playerRef.current !== null) {
return playerRef.current;
}
const player = new VideoPlayer();
playerRef.current = player;
return player;
}
// ...Qui, playerRef stesso è nullable. Tuttavia, dovresti riuscire a convincere il tuo type checker che non c’è alcun caso in cui getPlayer() restituisca null. Poi usa getPlayer() nei tuoi gestori di eventi.
Troubleshooting
Non riesco a ottenere un ref a un componente personalizzato
Se provi a passare un ref al tuo componente così:
const inputRef = useRef(null);
return <MyInput ref={inputRef} />;Potresti ottenere un errore nella console:
Per impostazione predefinita, i tuoi componenti non espongono ref ai nodi DOM al loro interno.
Per risolvere, trova il componente a cui vuoi ottenere un ref:
export default function MyInput({ value, onChange }) {
return (
<input
value={value}
onChange={onChange}
/>
);
}E poi aggiungi ref all’elenco delle props che il tuo componente accetta e passa ref come prop al componente integrato figlio pertinente, così:
function MyInput({ value, onChange, ref }) {
return (
<input
value={value}
onChange={onChange}
ref={ref}
/>
);
};
export default MyInput;Poi il componente genitore può ottenere un ref ad esso.
Leggi di più su accedere ai nodi DOM di un altro componente.