# useImperativeHandle: expose an API, not a ref

useImperativeHandle replaces a ref value with an object you choose, so the parent calls explicit methods and never receives the DOM node.

> Page: https://ui.eneawork.it/blog/react-useimperativehandle
> Markdown: https://ui.eneawork.it/blog/react-useimperativehandle.md

*2026-11-01*

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.

Il catalogo EneUI conta 111.985 componenti, 1.556 blocchi e 12.808 icone da 1.472 librerie, misurati da /api/stats il 1 novembre 2026. La cifra viene da una query all’endpoint, non da una stima: conta i record pubblicati e non dice quanti usino questo pattern correttamente.

## 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.

## FAQ

### 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.
