Menu

Componenti controllati e non controllati in React

Un input controllato prende il suo valore dallo stato React e cambia solo tramite onChange. Un input non controllato tiene il proprio valore nel DOM, e lo leggi con un ref o con FormData. Impara la differenza, gli avvisi più comuni e quando usare ciascuno.

Questa pagina include editor eseguibili: modifica, esegui e vedi subito l'output.

Un componente controllato è un elemento di form il cui valore vive nello stato React: passi value e aggiorni lo stato in onChange, quindi è React a decidere cosa mostra l'input. Un componente non controllato tiene il suo valore nel DOM, come l'HTML semplice: passi un defaultValue iniziale e leggi il valore attuale più tardi tramite un ref o FormData.

Scrivi in entrambi gli input. Il paragrafo segue il primo a ogni tasto, perché ogni modifica imposta lo stato e provoca un nuovo render. Il secondo input cambia solo nel DOM; React non esegue alcun rendering, e vedi il suo valore solo quando "Read both" lo chiede.

Input controllati

Con un input controllato, lo stato React è l'unica fonte di verità. Il flusso a ogni tasto è:

  1. L'utente scrive, e il browser genera un evento input.
  2. Il tuo gestore onChange legge e.target.value e chiama il setter.
  3. React esegue un nuovo render e riscrive il nuovo stato nel value dell'input.

Poiché il tuo codice sta in mezzo a quel ciclo, puoi fare cose che un input non controllato non può: rifiutare o rimodellare caratteri, mostrare il valore da un'altra parte, disabilitare un pulsante finché il valore non è valido, o impostare il valore dal codice (un pulsante "Clear", un suggerimento che l'utente clicca).

Prova a scrivere lettere: non compaiono mai, perché il gestore toglie tutto ciò che non è una cifra prima di impostare lo stato. Il pulsante Verify resta disabilitato finché non ci sono esattamente sei cifre.

Controllato è ciò che usano gli esempi di form della pagina sui form, ed è la scelta predefinita nella maggior parte del codice React.

Input non controllati

Un input non controllato funziona come l'HTML semplice. React lo renderizza una volta con defaultValue (o defaultChecked per checkbox e radio) e poi lo lascia stare. Per leggere il valore, tieni un ref all'elemento oppure leggi tutti i campi con nome dal form all'invio con FormData.

Non c'è stato per i campi e non c'è onChange. I valori vengono raccolti solo quando il form viene inviato. Togli la spunta alla checkbox e invia di nuovo: la chiave subscribe sparisce, perché una checkbox non spuntata non fa proprio parte di FormData.

Cambiare defaultValue dopo il primo rendering non ha effetto sull'input, perché React lo applica solo quando l'elemento viene creato. Per azzerare un form non controllato, chiama e.target.reset(), oppure dai al form una nuova key così React crea input nuovi.

Un input in cui non puoi scrivere

Se passi value ma non onChange, l'input è controllato, ma nulla aggiorna mai lo stato. React riscrive lo stesso valore dopo ogni tasto, quindi l'input sembra bloccato.

Prova a scrivere in ogni campo. Il primo non cambia. Il secondo è la soluzione per un input controllato, e mentre scrivi lì, il primo e l'ultimo campo lo seguono, perché tutti e tre leggono lo stesso stato. Il terzo accetta la digitazione perché è non controllato. Il quarto dichiara di proposito che non può essere modificato.

In sviluppo, React registra un avviso per il primo input: "You provided a value prop to a form field without an onChange handler". L'anteprima gira come una build di produzione, quindi qui non vedrai quell'avviso, ma lo vedrai nel tuo server di sviluppo.

Passare da non controllato a controllato

React decide se un input è controllato guardando value. Se value è undefined o null, l'input è non controllato. Quindi un input il cui value parte come undefined e poi diventa una stringa passa da non controllato a controllato durante la sua vita, e React avvisa in sviluppo: "A component is changing an uncontrolled input to be controlled".

L'avviso indica un bug reale. Tornare indietro nell'altra direzione, da una stringa a undefined, rende di nuovo l'input non controllato, e React smette di scriverci.

Scrivi qualcosa in entrambi gli input e premi ciascun pulsante Clear. Il secondo input si svuota. Il primo mantiene il suo testo: impostare lo stato a undefined lo ha reso non controllato, quindi React non controlla più ciò che mostra.

La fonte abituale di undefined sono dati non ancora caricati (value={user.name} prima che arrivi l'utente) o un campo di un oggetto che non esiste ancora. Due soluzioni:

const [name, setName] = useState('');   // start with a string
<input value={user?.name ?? ''} />       // or fall back to one

Per le checkbox la stessa regola vale per checked: fallo partire da false, non da undefined.

Gli input file sono sempre non controllati

Un <input type="file"> non può essere controllato, perché i browser non permettono a una pagina di impostarne il valore (una pagina che potesse scegliere file sul tuo disco sarebbe una falla di sicurezza). Leggi i file scelti da e.target.files in onChange, oppure tramite un ref quando il form viene inviato.

Scegli uno o due file dal tuo computer; non viene caricato nulla, l'esempio elenca solo nomi e dimensioni. L'unico valore che puoi impostare su un input file è la stringa vuota, ed è così che il pulsante Clear lo azzera.

Quando scegliere quale

ControllatoNon controllato
Il valore vive inLo stato ReactIl DOM
Impostare il valore inizialevalue / checkeddefaultValue / defaultChecked
Leggere il valoreIn qualsiasi momento, dallo statoCon un ref, o FormData all'invio
Rendering a ogni tastoSìNo
Cambiare il valore dal codiceImposta lo statoScrivi nel DOM tramite un ref
Adatto aValidazione dal vivo, formattazione, campi dipendentiForm semplici letti all'invio, input file, form action

Scegli controllato quando lo schermo deve reagire al valore mentre l'utente scrive. Scegli non controllato quando ti servono i valori solo alla fine, che è anche il modo in cui funzionano le form action di React 19: <form action={fn}> consegna alla tua funzione un FormData e poi azzera i campi non controllati.

Un rendering a ogni tasto sembra costoso, ma per un form normale non è un problema. Lo diventa solo quando un albero grande e lento esegue un nuovo render insieme all'input; in quel caso tieni lo stato vicino all'input, o sposta la parte lenta in un suo componente.

Le stesse due parole descrivono anche i tuoi componenti. Un componente che riceve il suo valore e un onChange dal genitore tramite props è controllato dal genitore; uno che tiene il proprio stato è non controllato. Spostare lo stato verso l'alto per rendere un componente controllato è l'argomento di sollevare lo stato.

Domande frequenti

Cos'è un componente controllato in React?

Un elemento di form il cui valore attuale arriva dallo stato React, impostato con value (o checked) e aggiornato tramite onChange. Lo stato React è l'unica fonte di verità, quindi conosci sempre il valore e puoi cambiarlo dal codice.

Cos'è un componente non controllato in React?

Un elemento di form che tiene il proprio valore nel DOM, come l'HTML semplice. Gli dai un valore iniziale con defaultValue (o defaultChecked) e leggi il valore attuale quando ti serve, tramite un ref o FormData all'invio.

Perché non riesco a scrivere nel mio input React?

Hai passato value senza un onChange. L'input è controllato, quindi React continua a rimettere il valore dello stato dopo ogni tasto. Aggiungi un onChange che aggiorna lo stato, passa a defaultValue, oppure aggiungi readOnly se davvero non deve cambiare.

Come risolvo "A component is changing an uncontrolled input to be controlled"?

Il value dell'input è partito come undefined (o null) e poi è diventato una stringa. Assicurati che sia sempre una stringa: fai partire lo stato da '', oppure scrivi value={name ?? ''}.

Devo usare input controllati o non controllati?

Usa input controllati quando la UI reagisce al valore mentre l'utente scrive: validazione, formattazione, un pulsante disabilitato, campi che dipendono l'uno dall'altro. Usa input non controllati quando ti servono i valori solo all'invio, e per gli input file, che sono sempre non controllati.

Illustrazione dei linguaggi di programmazione di Coddy

Impara a programmare con Coddy

INIZIA