React
useImperativeHandle: esporre un’API, non un ref
useImperativeHandle sostituisce il valore di un ref con un oggetto che scegli tu: il genitore chiama metodi espliciti e non riceve il nodo DOM.
In sintesi
- useImperativeHandle cambia il contenuto del ref, non il modo in cui viene passato.
- Esporre due metodi al posto del nodo riduce la superficie pubblica del componente e il numero di accoppiamenti.
- Da React 19 ref è una prop normale e forwardRef non serve più, mentre l’hook resta.
useImperativeHandle sostituisce il valore di un ref con un oggetto che scegli tu: il genitore chiama metodi espliciti e non riceve il nodo DOM. Conviene quando l’API pubblica deve restare più stretta di quella dell’elemento.
Cosa passa davvero in un ref
Un ref normale porta all’elemento: chi lo riceve può chiamare focus, rimuoverlo dal DOM, riscriverne gli attributi. Quel potere è più ampio di quanto il componente voglia concedere, e ogni metodo usato dal genitore diventa un accoppiamento che nessun tipo controlla.
Due metodi, per scelta
Un campo di testo che espone la selezione senza consegnare l’input:
const TextField = forwardRef(function TextField({ label }, ref) {
const inputRef = useRef(null);
// The parent gets focus and selectAll, nothing else.
useImperativeHandle(ref, () => ({
focus: () => inputRef.current?.focus(),
selectAll: () => inputRef.current?.select(),
}), []);
return (
{label}
);
});
Il genitore riceve due funzioni. Non può leggere il valore, non può cambiare il nodo, e il tipo del ref può dichiarare esattamente quei due metodi invece di HTMLInputElement.
Con React 19 ref è una prop
Dalla versione 19 ref arriva fra le props, quindi forwardRef non serve più. Il corpo dell’hook resta identico e il chiamante non cambia una riga.
function TextField({ label, ref }) {
const inputRef = useRef(null);
useImperativeHandle(ref, () => ({
focus: () => inputRef.current?.focus(),
selectAll: () => inputRef.current?.select(),
}), []);
return (
{label}
);
}
Quando è la scelta sbagliata
Se il genitore deve solo misurare l’elemento, un ref normale basta. Se deve reagire a un evento, una callback nelle props è più chiara. useImperativeHandle aggiunge un livello: si usa quando l’API deve essere più stretta del nodo, non per nascondere un ref che nessuno dovrebbe avere.
Il comando
Il pacchetto è su npm; il secondo comando stampa la versione risolta, così il primo esempio non gira su una major vecchia.
npm install react@19 react-dom@19
npm ls react
Record vivi nel catalogo
Tre record pubblicati che espongono un’API ristretta: otp-input concentra il focus su una casella, dialog apre e chiude senza consegnare il portale, expandable-tabs cambia scheda da fuori. Sono record fra i 111.985 componenti del catalogo.
Fonte e licenza
React è distribuito con licenza MIT. La pagina di riferimento su react.dev descrive useImperativeHandle come via di fuga e chiede di preferire la via dichiarativa quando esiste: quel consiglio è la regola di scelta, non un dettaglio.
La limitazione
Il valore del ref viene riassegnato al commit, non durante il render: un genitore che legge ref.current nel proprio render vede l’oggetto precedente, o null al primo passaggio. L’hook non risolve quella tempistica.
Dove continuare
Il confronto diretto fra ref e stato è in ref DOM vs stato; le regole di chiamata degli hook sono in regole degli hook; il caso in cui il ref attraversa l’albero è in portal per i modali.
Domande frequenti
useImperativeHandle sostituisce forwardRef?
No, lo completa: forwardRef inoltra il ref al componente, useImperativeHandle decide cosa quel ref contiene. Da React 19 il primo pezzo diventa una prop e resta solo l’hook.
Perché non passare direttamente il nodo DOM?
Perché il nodo espone decine di metodi e proprietà: chi lo riceve può smontarlo o riscriverne gli attributi. Un oggetto con due funzioni rende l’API pubblica piccola e verificabile.
Le funzioni esposte restano stabili fra i render?
Solo se il terzo argomento dell’hook non cambia. Con un array di dipendenze vuoto l’oggetto viene ricreato una volta; con dipendenze variabili cambia identità a ogni render.
Funziona anche in un componente classe?
No. In una classe si usa un ref oggetto e si assegnano i metodi in componentDidMount; l’hook vive solo nelle funzioni.
Serve un test per un’API imperativa?
Sì, un test che chiama il metodo e controlla il risultato finale, non l’oggetto: con Testing Library si chiama ref.current.focus() e si verifica document.activeElement.