Component
Component è la classe base per i componenti React definiti come classi JavaScript. I componenti classe sono ancora supportati da React, ma non consigliamo di usarli nel codice nuovo.
class Greeting extends Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}- Reference
Componentcontextpropsstateconstructor(props)componentDidCatch(error, info)componentDidMount()componentDidUpdate(prevProps, prevState, snapshot?)componentWillMount()componentWillReceiveProps(nextProps)componentWillUpdate(nextProps, nextState)componentWillUnmount()forceUpdate(callback?)getSnapshotBeforeUpdate(prevProps, prevState)render()setState(nextState, callback?)shouldComponentUpdate(nextProps, nextState, nextContext)UNSAFE_componentWillMount()UNSAFE_componentWillReceiveProps(nextProps, nextContext)UNSAFE_componentWillUpdate(nextProps, nextState)static contextTypestatic defaultPropsstatic getDerivedStateFromError(error)static getDerivedStateFromProps(props, state)
- Usage
- Alternatives
Reference
Component
Per definire un componente React come classe, estendi la classe integrata Component e definisci un metodo render:
import { Component } from 'react';
class Greeting extends Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}Solo il metodo render è obbligatorio; gli altri metodi sono opzionali.
context
Il context di un componente classe è disponibile come this.context. È disponibile solo se specifichi quale context vuoi ricevere usando static contextType.
Un componente classe può leggere un solo context alla volta.
class Button extends Component {
static contextType = ThemeContext;
render() {
const theme = this.context;
const className = 'button-' + theme;
return (
<button className={className}>
{this.props.children}
</button>
);
}
}props
Le props passate a un componente classe sono disponibili come this.props.
class Greeting extends Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}
<Greeting name="Taylor" />state
Lo state di un componente classe è disponibile come this.state. Il campo state deve essere un oggetto. Non mutare lo state direttamente. Se vuoi cambiare lo state, chiama setState con il nuovo state.
class Counter extends Component {
state = {
age: 42,
};
handleAgeChange = () => {
this.setState({
age: this.state.age + 1
});
};
render() {
return (
<>
<button onClick={this.handleAgeChange}>
Incrementa età
</button>
<p>Hai {this.state.age} anni.</p>
</>
);
}
}constructor(props)
Il constructor viene eseguito prima che il tuo componente classe venga montato (aggiunto allo schermo). Di solito, in React un constructor serve solo a due scopi: ti permette di dichiarare lo state e di associare i metodi della classe all’istanza:
class Counter extends Component {
constructor(props) {
super(props);
this.state = { counter: 0 };
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
// ...
}Se usi la sintassi JavaScript moderna, i constructor sono raramente necessari. Puoi invece riscrivere il codice sopra usando la sintassi dei campi pubblici di classe, supportata sia dai browser moderni sia da strumenti come Babel:
class Counter extends Component {
state = { counter: 0 };
handleClick = () => {
// ...
}Un constructor non dovrebbe contenere effetti collaterali o sottoscrizioni.
Parameters
props: Le props iniziali del componente.
Returns
constructor non dovrebbe restituire nulla.
Caveats
-
Non eseguire effetti collaterali o sottoscrizioni nel constructor. Usa invece
componentDidMountper questo. -
All’interno di un constructor, devi chiamare
super(props)prima di qualsiasi altra istruzione. Se non lo fai,this.propssaràundefinedmentre il constructor è in esecuzione, il che può creare confusione e bug. -
Il constructor è l’unico punto in cui puoi assegnare
this.statedirettamente. In tutti gli altri metodi devi usarethis.setState(). Non chiamaresetStatenel constructor. -
Quando usi la renderizzazione lato server, il constructor viene eseguito anche sul server, seguito dal metodo
render. Tuttavia, metodi del lifecycle comecomponentDidMountocomponentWillUnmountnon vengono eseguiti sul server. -
Quando Strict Mode è attivo, React chiamerà
constructordue volte in sviluppo e poi scarterà una delle istanze. Questo ti aiuta a notare gli effetti collaterali accidentali che devono essere spostati fuori dalconstructor.
componentDidCatch(error, info)
Se definisci componentDidCatch, React lo chiamerà quando un componente figlio (inclusi i discendenti lontani) lancia un errore durante la renderizzazione. Questo ti permette di registrare l’errore in un servizio di segnalazione errori in produzione.
Di solito viene usato insieme a static getDerivedStateFromError, che ti permette di aggiornare lo state in risposta a un errore e mostrare un messaggio di errore all’utente. Un componente con questi metodi si chiama contenitore di errori.
Parameters
-
error: L’errore che è stato lanciato. In pratica, di solito sarà un’istanza diError, ma non è garantito perché JavaScript permette dithrowqualsiasi valore, incluse stringhe o persinonull. -
info: Un oggetto che contiene informazioni aggiuntive sull’errore. Il suo campocomponentStackcontiene uno stack trace con il componente che ha lanciato l’errore, nonché i nomi e le posizioni nel sorgente di tutti i suoi componenti genitore. In produzione, i nomi dei componenti saranno minificati. Se configuri la segnalazione errori in produzione, puoi decodificare lo stack dei componenti usando le sourcemap come faresti per gli stack trace JavaScript normali.
Returns
componentDidCatch non dovrebbe restituire nulla.
Caveats
-
In passato era comune chiamare
setStatedentrocomponentDidCatchper aggiornare l’UI e mostrare il messaggio di errore di fallback. Questo è deprecato a favore della definizione distatic getDerivedStateFromError. -
Le build di produzione e sviluppo di React differiscono leggermente nel modo in cui
componentDidCatchgestisce gli errori. In sviluppo, gli errori risaliranno fino awindow, il che significa che qualsiasiwindow.onerrorowindow.addEventListener('error', callback)intercetterà gli errori catturati dacomponentDidCatch. In produzione, invece, gli errori non risaliranno, il che significa che qualsiasi gestore di errori antenato riceverà solo errori non catturati esplicitamente dacomponentDidCatch.
componentDidMount()
Se definisci il metodo componentDidMount, React lo chiamerà quando il tuo componente viene aggiunto (montato) allo schermo. È un punto comune per avviare il fetch dei dati, impostare sottoscrizioni o manipolare i nodi DOM.
Se implementi componentDidMount, di solito devi implementare anche altri metodi del lifecycle per evitare bug. Ad esempio, se componentDidMount legge dello state o delle props, devi anche implementare componentDidUpdate per gestirne i cambiamenti e componentWillUnmount per ripulire ciò che componentDidMount stava facendo.
class ChatRoom extends Component {
state = {
serverUrl: 'https://localhost:1234'
};
componentDidMount() {
this.setupConnection();
}
componentDidUpdate(prevProps, prevState) {
if (
this.props.roomId !== prevProps.roomId ||
this.state.serverUrl !== prevState.serverUrl
) {
this.destroyConnection();
this.setupConnection();
}
}
componentWillUnmount() {
this.destroyConnection();
}
// ...
}Parameters
componentDidMount non accetta parametri.
Returns
componentDidMount non dovrebbe restituire nulla.
Caveats
-
Quando Strict Mode è attivo, in sviluppo React chiamerà
componentDidMount, poi chiamerà immediatamentecomponentWillUnmount, e poi chiamerà di nuovocomponentDidMount. Questo ti aiuta a notare se hai dimenticato di implementarecomponentWillUnmounto se la sua logica non “rispecchia” completamente ciò che facomponentDidMount. -
Anche se puoi chiamare
setStateimmediatamente incomponentDidMount, è meglio evitarlo quando puoi. Avvierà una renderizzazione extra, ma avverrà prima che il browser aggiorni lo schermo. Questo garantisce che, anche serenderverrà chiamato due volte in questo caso, l’utente non vedrà lo state intermedio. Usa questo pattern con cautela perché spesso causa problemi di prestazioni. Nella maggior parte dei casi, dovresti poter assegnare lo state iniziale nelconstructor. Tuttavia, può essere necessario per casi come modali e tooltip quando devi misurare un nodo DOM prima di renderizzare qualcosa che dipende dalle sue dimensioni o posizione.
componentDidUpdate(prevProps, prevState, snapshot?)
Se definisci il metodo componentDidUpdate, React lo chiamerà immediatamente dopo che il tuo componente è stato ri-renderizzato con props o state aggiornati. Questo metodo non viene chiamato per la renderizzazione iniziale.
Puoi usarlo per manipolare il DOM dopo un aggiornamento. È anche un punto comune per fare richieste di rete, purché confronti le props attuali con quelle precedenti (ad esempio, una richiesta di rete potrebbe non essere necessaria se le props non sono cambiate). Di solito lo usi insieme a componentDidMount e componentWillUnmount:
class ChatRoom extends Component {
state = {
serverUrl: 'https://localhost:1234'
};
componentDidMount() {
this.setupConnection();
}
componentDidUpdate(prevProps, prevState) {
if (
this.props.roomId !== prevProps.roomId ||
this.state.serverUrl !== prevState.serverUrl
) {
this.destroyConnection();
this.setupConnection();
}
}
componentWillUnmount() {
this.destroyConnection();
}
// ...
}Parameters
-
prevProps: Props prima dell’aggiornamento. ConfrontaprevPropsconthis.propsper determinare cosa è cambiato. -
prevState: State prima dell’aggiornamento. ConfrontaprevStateconthis.stateper determinare cosa è cambiato. -
snapshot: Se hai implementatogetSnapshotBeforeUpdate,snapshotconterrà il valore restituito da quel metodo. Altrimenti, saràundefined.
Returns
componentDidUpdate non dovrebbe restituire nulla.
Caveats
-
componentDidUpdatenon verrà chiamato seshouldComponentUpdateè definito e restituiscefalse. -
La logica dentro
componentDidUpdatedovrebbe di solito essere racchiusa in condizioni che confrontanothis.propsconprevPropsethis.stateconprevState. Altrimenti c’è il rischio di creare loop infiniti. -
Anche se puoi chiamare
setStateimmediatamente incomponentDidUpdate, è meglio evitarlo quando puoi. Avvierà una renderizzazione extra, ma avverrà prima che il browser aggiorni lo schermo. Questo garantisce che, anche serenderverrà chiamato due volte in questo caso, l’utente non vedrà lo state intermedio. Questo pattern spesso causa problemi di prestazioni, ma può essere necessario per casi rari come modali e tooltip quando devi misurare un nodo DOM prima di renderizzare qualcosa che dipende dalle sue dimensioni o posizione.
componentWillMount()
componentWillReceiveProps(nextProps)
componentWillUpdate(nextProps, nextState)
componentWillUnmount()
Se definisci il metodo componentWillUnmount, React lo chiamerà prima che il tuo componente venga rimosso (smontato) dallo schermo. È un punto comune per annullare il fetch dei dati o rimuovere sottoscrizioni.
La logica dentro componentWillUnmount dovrebbe “rispecchiare” la logica dentro componentDidMount. Ad esempio, se componentDidMount imposta una sottoscrizione, componentWillUnmount dovrebbe ripulire quella sottoscrizione. Se la logica di cleanup in componentWillUnmount legge delle props o dello state, di solito dovrai anche implementare componentDidUpdate per ripulire le risorse (come le sottoscrizioni) corrispondenti alle vecchie props e allo state.
class ChatRoom extends Component {
state = {
serverUrl: 'https://localhost:1234'
};
componentDidMount() {
this.setupConnection();
}
componentDidUpdate(prevProps, prevState) {
if (
this.props.roomId !== prevProps.roomId ||
this.state.serverUrl !== prevState.serverUrl
) {
this.destroyConnection();
this.setupConnection();
}
}
componentWillUnmount() {
this.destroyConnection();
}
// ...
}Parameters
componentWillUnmount non accetta parametri.
Returns
componentWillUnmount non dovrebbe restituire nulla.
Caveats
- Quando Strict Mode è attivo, in sviluppo React chiamerà
componentDidMount, poi chiamerà immediatamentecomponentWillUnmount, e poi chiamerà di nuovocomponentDidMount. Questo ti aiuta a notare se hai dimenticato di implementarecomponentWillUnmounto se la sua logica non “rispecchia” completamente ciò che facomponentDidMount.
forceUpdate(callback?)
Forza la ri-renderizzazione di un componente.
Di solito non è necessario. Se il metodo render del tuo componente legge solo da this.props, this.state o this.context,, verrà ri-renderizzato automaticamente quando chiami setState dentro il tuo componente o uno dei suoi genitori. Tuttavia, se il metodo render del tuo componente legge direttamente da una sorgente dati esterna, devi dire a React di aggiornare l’interfaccia utente quando quella sorgente dati cambia. È ciò che ti permette di fare forceUpdate.
Cerca di evitare ogni uso di forceUpdate e leggi solo da this.props e this.state in render.
Parameters
- optional
callback: Se specificato, React chiamerà lacallbackche hai fornito dopo che l’aggiornamento è stato committato.
Returns
forceUpdate non restituisce nulla.
Caveats
- Se chiami
forceUpdate, React ri-renderizzerà senza chiamareshouldComponentUpdate.
getSnapshotBeforeUpdate(prevProps, prevState)
Se implementi getSnapshotBeforeUpdate, React lo chiamerà immediatamente prima di aggiornare il DOM. Permette al tuo componente di catturare alcune informazioni dal DOM (ad esempio, la posizione di scroll) prima che vengano potenzialmente modificate. Qualsiasi valore restituito da questo metodo del lifecycle verrà passato come parametro a componentDidUpdate.
Ad esempio, puoi usarlo in un’UI come un thread di chat che deve preservare la posizione di scroll durante gli aggiornamenti:
class ScrollingList extends React.Component {
constructor(props) {
super(props);
this.listRef = React.createRef();
}
getSnapshotBeforeUpdate(prevProps, prevState) {
// Stiamo aggiungendo nuovi elementi alla lista?
// Cattura la posizione di scroll così possiamo regolarla in seguito.
if (prevProps.list.length < this.props.list.length) {
const list = this.listRef.current;
return list.scrollHeight - list.scrollTop;
}
return null;
}
componentDidUpdate(prevProps, prevState, snapshot) {
// Se abbiamo un valore snapshot, abbiamo appena aggiunto nuovi elementi.
// Regola lo scroll così questi nuovi elementi non spingono fuori vista quelli vecchi.
// (snapshot qui è il valore restituito da getSnapshotBeforeUpdate)
if (snapshot !== null) {
const list = this.listRef.current;
list.scrollTop = list.scrollHeight - snapshot;
}
}
render() {
return (
<div ref={this.listRef}>{/* ...contents... */}</div>
);
}
}Nell’esempio sopra, è importante leggere la proprietà scrollHeight direttamente in getSnapshotBeforeUpdate. Non è sicuro leggerla in render, UNSAFE_componentWillReceiveProps o UNSAFE_componentWillUpdate perché c’è un potenziale intervallo di tempo tra la chiamata di questi metodi e l’aggiornamento del DOM da parte di React.
Parameters
-
prevProps: Props prima dell’aggiornamento. ConfrontaprevPropsconthis.propsper determinare cosa è cambiato. -
prevState: State prima dell’aggiornamento. ConfrontaprevStateconthis.stateper determinare cosa è cambiato.
Returns
Dovresti restituire un valore snapshot di qualsiasi tipo tu voglia, oppure null. Il valore restituito verrà passato come terzo argomento a componentDidUpdate.
Caveats
getSnapshotBeforeUpdatenon verrà chiamato seshouldComponentUpdateè definito e restituiscefalse.
render()
Il metodo render è l’unico metodo obbligatorio in un componente classe.
Il metodo render dovrebbe specificare cosa vuoi che appaia sullo schermo, ad esempio:
import { Component } from 'react';
class Greeting extends Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}React può chiamare render in qualsiasi momento, quindi non dovresti assumere che venga eseguito in un momento particolare. Di solito, il metodo render dovrebbe restituire un pezzo di JSX, ma sono supportati anche alcuni altri tipi di ritorno (come le stringhe). Per calcolare il JSX restituito, il metodo render può leggere this.props, this.state e this.context.
Dovresti scrivere il metodo render come una funzione pura, il che significa che dovrebbe restituire lo stesso risultato se props, state e context sono gli stessi. Non dovrebbe inoltre contenere effetti collaterali (come impostare sottoscrizioni) o interagire con le API del browser. Gli effetti collaterali dovrebbero avvenire nei gestori di eventi o in metodi come componentDidMount.
Parameters
render non accetta parametri.
Returns
render può restituire qualsiasi nodo React valido. Questo include elementi React come <div />, stringhe, numeri, portals, nodi vuoti (null, undefined, true e false) e array di nodi React.
Caveats
-
renderdovrebbe essere scritto come una funzione pura di props, state e context. Non dovrebbe avere effetti collaterali. -
rendernon verrà chiamato seshouldComponentUpdateè definito e restituiscefalse. -
Quando Strict Mode è attivo, React chiamerà
renderdue volte in sviluppo e poi scarterà uno dei risultati. Questo ti aiuta a notare gli effetti collaterali accidentali che devono essere spostati fuori dal metodorender. -
Non c’è corrispondenza uno-a-uno tra la chiamata a
rendere la successiva chiamata acomponentDidMountocomponentDidUpdate. Alcuni risultati delle chiamate arenderpossono essere scartati da React quando è vantaggioso.
setState(nextState, callback?)
Chiama setState per aggiornare lo state del tuo componente React.
class Form extends Component {
state = {
name: 'Taylor',
};
handleNameChange = (e) => {
const newName = e.target.value;
this.setState({
name: newName
});
}
render() {
return (
<>
<input value={this.state.name} onChange={this.handleNameChange} />
<p>Hello, {this.state.name}.</p>
</>
);
}
}setState accoda le modifiche allo state del componente. Dice a React che questo componente e i suoi figli devono essere ri-renderizzati con il nuovo state. È il modo principale in cui aggiornerai l’interfaccia utente in risposta alle interazioni.
Puoi anche passare una funzione a setState. Ti permette di aggiornare lo state in base allo state precedente:
handleIncreaseAge = () => {
this.setState(prevState => {
return {
age: prevState.age + 1
};
});
}Non devi farlo, ma è utile se vuoi aggiornare lo state più volte durante lo stesso evento.
Parameters
-
nextState: Un oggetto o una funzione.- Se passi un oggetto come
nextState, verrà unito superficialmente athis.state. - Se passi una funzione come
nextState, verrà trattata come una funzione updater. Deve essere pura, dovrebbe accettare lo state e le props in sospeso come argomenti e dovrebbe restituire l’oggetto da unire superficialmente athis.state. React metterà la tua funzione updater in coda e ri-renderizzerà il tuo componente. Durante la prossima renderizzazione, React calcolerà il prossimo state applicando tutti gli updater in coda allo state precedente.
- Se passi un oggetto come
-
optional
callback: Se specificato, React chiamerà lacallbackche hai fornito dopo che l’aggiornamento è stato committato.
Returns
setState non restituisce nulla.
Caveats
-
Pensa a
setStatecome a una richiesta piuttosto che a un comando immediato di aggiornamento del componente. Quando più componenti aggiornano il loro state in risposta a un evento, React raggrupperà i loro aggiornamenti e li ri-renderizzerà insieme in un unico passaggio alla fine dell’evento. Nel raro caso in cui devi forzare l’applicazione sincrona di un particolare aggiornamento dello state, puoi avvolgerlo influshSync, ma questo potrebbe penalizzare le prestazioni. -
setStatenon aggiornathis.stateimmediatamente. Questo rende la lettura dithis.statesubito dopo aver chiamatosetStateun potenziale problema. Usa invececomponentDidUpdateo l’argomentocallbackdi setState, entrambi garantiti per essere eseguiti dopo che l’aggiornamento è stato applicato. Se devi impostare lo state in base allo state precedente, puoi passare una funzione anextStatecome descritto sopra.
shouldComponentUpdate(nextProps, nextState, nextContext)
Se definisci shouldComponentUpdate, React lo chiamerà per determinare se una ri-renderizzazione può essere saltata.
Se sei sicuro di volerlo scrivere a mano, puoi confrontare this.props con nextProps e this.state con nextState e restituire false per dire a React che l’aggiornamento può essere saltato.
class Rectangle extends Component {
state = {
isHovered: false
};
shouldComponentUpdate(nextProps, nextState) {
if (
nextProps.position.x === this.props.position.x &&
nextProps.position.y === this.props.position.y &&
nextProps.size.width === this.props.size.width &&
nextProps.size.height === this.props.size.height &&
nextState.isHovered === this.state.isHovered
) {
// Nulla è cambiato, quindi una ri-renderizzazione non è necessaria
return false;
}
return true;
}
// ...
}React chiama shouldComponentUpdate prima della renderizzazione quando vengono ricevute nuove props o state. Il valore predefinito è true. Questo metodo non viene chiamato per la renderizzazione iniziale o quando viene usato forceUpdate.
Parameters
nextProps: Le prossime props con cui il componente sta per essere renderizzato. ConfrontanextPropsconthis.propsper determinare cosa è cambiato.nextState: Il prossimo state con cui il componente sta per essere renderizzato. ConfrontanextStateconthis.stateper determinare cosa è cambiato.nextContext: Il prossimo context con cui il componente sta per essere renderizzato. ConfrontanextContextconthis.contextper determinare cosa è cambiato. Disponibile solo se specifichistatic contextType.
Returns
Restituisci true se vuoi che il componente venga ri-renderizzato. Questo è il comportamento predefinito.
Restituisci false per dire a React che la ri-renderizzazione può essere saltata.
Caveats
-
Questo metodo esiste solo come ottimizzazione delle prestazioni. Se il tuo componente si rompe senza di esso, risolvi prima quello.
-
Considera l’uso di
PureComponentinvece di scrivereshouldComponentUpdatea mano.PureComponentconfronta superficialmente props e state e riduce la probabilità di saltare un aggiornamento necessario. -
Non consigliamo di fare controlli di uguaglianza profonda o di usare
JSON.stringifyinshouldComponentUpdate. Rende le prestazioni imprevedibili e dipendenti dalla struttura dati di ogni prop e state. Nel caso migliore, rischi di introdurre blocchi di diversi secondi nella tua applicazione, e nel caso peggiore rischi di farla crashare. -
Restituire
falsenon impedisce ai componenti figli di essere ri-renderizzati quando cambia il loro state. -
Restituire
falsenon garantisce che il componente non verrà ri-renderizzato. React userà il valore di ritorno come suggerimento, ma potrebbe comunque scegliere di ri-renderizzare il tuo componente se ha senso per altri motivi.
UNSAFE_componentWillMount()
Se definisci UNSAFE_componentWillMount, React lo chiamerà immediatamente dopo il constructor. Esiste solo per ragioni storiche e non dovrebbe essere usato in codice nuovo. Usa invece una delle alternative:
- Per inizializzare lo state, dichiara
statecome campo di classe o impostathis.statedentro ilconstructor. - Se devi eseguire un effetto collaterale o impostare una sottoscrizione, sposta quella logica in
componentDidMount.
Vedi esempi di migrazione dai lifecycle non sicuri.
Parameters
UNSAFE_componentWillMount non accetta parametri.
Returns
UNSAFE_componentWillMount non dovrebbe restituire nulla.
Caveats
-
UNSAFE_componentWillMountnon verrà chiamato se il componente implementastatic getDerivedStateFromPropsogetSnapshotBeforeUpdate. -
Nonostante il nome,
UNSAFE_componentWillMountnon garantisce che il componente verrà montato se la tua app usa funzionalità React moderne comeSuspense. Se un tentativo di renderizzazione viene sospeso (ad esempio, perché il codice di un componente figlio non è ancora stato caricato), React scarterà l’albero in corso e tenterà di costruire il componente da zero durante il prossimo tentativo. Ecco perché questo metodo è “non sicuro”. Il codice che dipende dal montaggio (come aggiungere una sottoscrizione) dovrebbe andare incomponentDidMount. -
UNSAFE_componentWillMountè l’unico metodo del lifecycle eseguito durante la renderizzazione lato server. Per tutti gli scopi pratici, è identico alconstructor, quindi dovresti usare ilconstructorper questo tipo di logica.
UNSAFE_componentWillReceiveProps(nextProps, nextContext)
Se definisci UNSAFE_componentWillReceiveProps, React lo chiamerà quando il componente riceve nuove props. Esiste solo per ragioni storiche e non dovrebbe essere usato in codice nuovo. Usa invece una delle alternative:
- Se devi eseguire un effetto collaterale (ad esempio, fetch di dati, eseguire un’animazione o reinizializzare una sottoscrizione) in risposta a cambiamenti delle props, sposta quella logica in
componentDidUpdate. - Se devi evitare di ricalcolare alcuni dati solo quando una prop cambia, usa un helper di memorizzazione.
- Se devi “resettare” dello state quando una prop cambia, considera un componente completamente controllato o completamente non controllato con una key.
- Se devi “regolare” dello state quando una prop cambia, verifica se puoi calcolare tutte le informazioni necessarie dalle sole props durante la renderizzazione. Se non puoi, usa
static getDerivedStateFromProps.
Vedi esempi di migrazione dai lifecycle non sicuri.
Parameters
nextProps: Le prossime props che il componente sta per ricevere dal suo componente genitore. ConfrontanextPropsconthis.propsper determinare cosa è cambiato.nextContext: Il prossimo context che il componente sta per ricevere dal provider più vicino. ConfrontanextContextconthis.contextper determinare cosa è cambiato. Disponibile solo se specifichistatic contextType.
Returns
UNSAFE_componentWillReceiveProps non dovrebbe restituire nulla.
Caveats
-
UNSAFE_componentWillReceivePropsnon verrà chiamato se il componente implementastatic getDerivedStateFromPropsogetSnapshotBeforeUpdate. -
Nonostante il nome,
UNSAFE_componentWillReceivePropsnon garantisce che il componente riceverà quelle props se la tua app usa funzionalità React moderne comeSuspense. Se un tentativo di renderizzazione viene sospeso (ad esempio, perché il codice di un componente figlio non è ancora stato caricato), React scarterà l’albero in corso e tenterà di costruire il componente da zero durante il prossimo tentativo. Al momento del prossimo tentativo di renderizzazione, le props potrebbero essere diverse. Ecco perché questo metodo è “non sicuro”. Il codice che dovrebbe essere eseguito solo per aggiornamenti committati (come resettare una sottoscrizione) dovrebbe andare incomponentDidUpdate. -
UNSAFE_componentWillReceivePropsnon significa che il componente ha ricevuto props diverse rispetto all’ultima volta. Devi confrontare tu stessonextPropsethis.propsper verificare se qualcosa è cambiato. -
React non chiama
UNSAFE_componentWillReceivePropscon le props iniziali durante il montaggio. Chiama questo metodo solo se alcune props del componente stanno per essere aggiornate. Ad esempio, chiamaresetStategeneralmente non attivaUNSAFE_componentWillReceivePropsdentro lo stesso componente.
UNSAFE_componentWillUpdate(nextProps, nextState)
Se definisci UNSAFE_componentWillUpdate, React lo chiamerà prima di renderizzare con le nuove props o state. Esiste solo per ragioni storiche e non dovrebbe essere usato in codice nuovo. Usa invece una delle alternative:
- Se devi eseguire un effetto collaterale (ad esempio, fetch di dati, eseguire un’animazione o reinizializzare una sottoscrizione) in risposta a cambiamenti di props o state, sposta quella logica in
componentDidUpdate. - Se devi leggere alcune informazioni dal DOM (ad esempio, per salvare la posizione di scroll attuale) così da poterle usare in
componentDidUpdatein seguito, leggile dentrogetSnapshotBeforeUpdate.
Vedi esempi di migrazione dai lifecycle non sicuri.
Parameters
nextProps: Le prossime props con cui il componente sta per essere renderizzato. ConfrontanextPropsconthis.propsper determinare cosa è cambiato.nextState: Il prossimo state con cui il componente sta per essere renderizzato. ConfrontanextStateconthis.stateper determinare cosa è cambiato.
Returns
UNSAFE_componentWillUpdate non dovrebbe restituire nulla.
Caveats
-
UNSAFE_componentWillUpdatenon verrà chiamato seshouldComponentUpdateè definito e restituiscefalse. -
UNSAFE_componentWillUpdatenon verrà chiamato se il componente implementastatic getDerivedStateFromPropsogetSnapshotBeforeUpdate. -
Non è supportato chiamare
setState(o qualsiasi metodo che porti a chiamaresetState, come eseguire il dispatch di un’azione Redux) durantecomponentWillUpdate. -
Nonostante il nome,
UNSAFE_componentWillUpdatenon garantisce che il componente verrà aggiornato se la tua app usa funzionalità React moderne comeSuspense. Se un tentativo di renderizzazione viene sospeso (ad esempio, perché il codice di un componente figlio non è ancora stato caricato), React scarterà l’albero in corso e tenterà di costruire il componente da zero durante il prossimo tentativo. Al momento del prossimo tentativo di renderizzazione, props e state potrebbero essere diversi. Ecco perché questo metodo è “non sicuro”. Il codice che dovrebbe essere eseguito solo per aggiornamenti committati (come resettare una sottoscrizione) dovrebbe andare incomponentDidUpdate. -
UNSAFE_componentWillUpdatenon significa che il componente ha ricevuto props o state diversi rispetto all’ultima volta. Devi confrontare tu stessonextPropsconthis.propsenextStateconthis.stateper verificare se qualcosa è cambiato. -
React non chiama
UNSAFE_componentWillUpdatecon props e state iniziali durante il montaggio.
static contextType
Se vuoi leggere this.context dal tuo componente classe, devi specificare quale context deve leggere. Il context che specifichi come static contextType deve essere un valore creato in precedenza da createContext.
class Button extends Component {
static contextType = ThemeContext;
render() {
const theme = this.context;
const className = 'button-' + theme;
return (
<button className={className}>
{this.props.children}
</button>
);
}
}static defaultProps
Puoi definire static defaultProps per impostare le props predefinite per la classe. Verranno usate per props undefined e mancanti, ma non per props null.
Ad esempio, ecco come definire che la prop color dovrebbe avere come valore predefinito 'blue':
class Button extends Component {
static defaultProps = {
color: 'blue'
};
render() {
return <button className={this.props.color}>click me</button>;
}
}Se la prop color non viene fornita o è undefined, verrà impostata per impostazione predefinita a 'blue':
<>
{/* this.props.color is "blue" */}
<Button />
{/* this.props.color is "blue" */}
<Button color={undefined} />
{/* this.props.color is null */}
<Button color={null} />
{/* this.props.color is "red" */}
<Button color="red" />
</>static getDerivedStateFromError(error)
Se definisci static getDerivedStateFromError, React lo chiamerà quando un componente figlio (inclusi i discendenti lontani) lancia un errore durante la renderizzazione. Ti permette di mostrare un messaggio di errore invece di cancellare l’UI.
Di solito viene usato insieme a componentDidCatch, che ti permette di inviare il report dell’errore a un servizio di analytics. Un componente con questi metodi si chiama contenitore di errori.
Parameters
error: L’errore che è stato lanciato. In pratica, di solito sarà un’istanza diError, ma non è garantito perché JavaScript permette dithrowqualsiasi valore, incluse stringhe o persinonull.
Returns
static getDerivedStateFromError dovrebbe restituire lo state che indica al componente di mostrare il messaggio di errore.
Caveats
static getDerivedStateFromErrordovrebbe essere una funzione pura. Se vuoi eseguire un effetto collaterale (ad esempio, chiamare un servizio di analytics), devi anche implementarecomponentDidCatch.
static getDerivedStateFromProps(props, state)
Se definisci static getDerivedStateFromProps, React lo chiamerà subito prima di chiamare render,, sia al montaggio iniziale sia agli aggiornamenti successivi. Dovrebbe restituire un oggetto per aggiornare lo state, oppure null per non aggiornare nulla.
Questo metodo esiste per casi d’uso rari in cui lo state dipende da cambiamenti delle props nel tempo. Ad esempio, questo componente Form resetta lo state email quando cambia la prop userID:
class Form extends Component {
state = {
email: this.props.defaultEmail,
prevUserID: this.props.userID
};
static getDerivedStateFromProps(props, state) {
// Ogni volta che l'utente corrente cambia,
// resetta le parti dello state legate a quell'utente.
// In questo semplice esempio, è solo l'email.
if (props.userID !== state.prevUserID) {
return {
prevUserID: props.userID,
email: props.defaultEmail
};
}
return null;
}
// ...
}Nota che questo pattern richiede di mantenere un valore precedente della prop (come userID) nello state (come prevUserID).
Parameters
props: Le prossime props con cui il componente sta per essere renderizzato.state: Il prossimo state con cui il componente sta per essere renderizzato.
Returns
static getDerivedStateFromProps restituisce un oggetto per aggiornare lo state, oppure null per non aggiornare nulla.
Caveats
-
Questo metodo viene eseguito a ogni renderizzazione, indipendentemente dalla causa. Questo è diverso da
UNSAFE_componentWillReceiveProps, che viene eseguito solo quando il genitore causa una ri-renderizzazione e non come risultato di unsetStatelocale. -
Questo metodo non ha accesso all’istanza del componente. Se vuoi, puoi riutilizzare del codice tra
static getDerivedStateFromPropse gli altri metodi della classe estraendo funzioni pure delle props e dello state del componente fuori dalla definizione della classe.
Usage
Definire un componente classe
Per definire un componente React come classe, estendi la classe integrata Component e definisci un metodo render:
import { Component } from 'react';
class Greeting extends Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}React chiamerà il tuo metodo render ogni volta che deve capire cosa mostrare sullo schermo. Di solito, restituirai del JSX da esso. Il tuo metodo render dovrebbe essere una funzione pura: dovrebbe calcolare solo il JSX.
Analogamente ai componenti funzione, un componente classe può ricevere informazioni tramite props dal suo componente genitore. Tuttavia, la sintassi per leggere le props è diversa. Ad esempio, se il componente genitore renderizza <Greeting name="Taylor" />, puoi leggere la prop name da this.props, come this.props.name:
import { Component } from 'react'; class Greeting extends Component { render() { return <h1>Hello, {this.props.name}!</h1>; } } export default function App() { return ( <> <Greeting name="Sara" /> <Greeting name="Cahal" /> <Greeting name="Edite" /> </> ); }
Nota che gli Hooks (funzioni che iniziano con use, come useState) non sono supportati dentro i componenti classe.
Aggiungere lo state a un componente classe
Per aggiungere state a una classe, assegna un oggetto a una proprietà chiamata state. Per aggiornare lo state, chiama this.setState.
import { Component } from 'react'; export default class Counter extends Component { state = { name: 'Taylor', age: 42, }; handleNameChange = (e) => { this.setState({ name: e.target.value }); } handleAgeChange = () => { this.setState({ age: this.state.age + 1 }); }; render() { return ( <> <input value={this.state.name} onChange={this.handleNameChange} /> <button onClick={this.handleAgeChange}> Incrementa età </button> <p>Ciao, {this.state.name}. Hai {this.state.age} anni.</p> </> ); } }
Aggiungere metodi del lifecycle a un componente classe
Ci sono alcuni metodi speciali che puoi definire sulla tua classe.
Se definisci il metodo componentDidMount, React lo chiamerà quando il tuo componente viene aggiunto (montato) allo schermo. React chiamerà componentDidUpdate dopo che il tuo componente è stato ri-renderizzato a causa di props o state cambiati. React chiamerà componentWillUnmount dopo che il tuo componente è stato rimosso (smontato) dallo schermo.
Se implementi componentDidMount, di solito devi implementare tutti e tre i metodi del lifecycle per evitare bug. Ad esempio, se componentDidMount legge dello state o delle props, devi anche implementare componentDidUpdate per gestirne i cambiamenti e componentWillUnmount per ripulire ciò che componentDidMount stava facendo.
Ad esempio, questo componente ChatRoom mantiene una connessione chat sincronizzata con props e state:
import { Component } from 'react'; import { createConnection } from './chat.js'; export default class ChatRoom extends Component { state = { serverUrl: 'https://localhost:1234' }; componentDidMount() { this.setupConnection(); } componentDidUpdate(prevProps, prevState) { if ( this.props.roomId !== prevProps.roomId || this.state.serverUrl !== prevState.serverUrl ) { this.destroyConnection(); this.setupConnection(); } } componentWillUnmount() { this.destroyConnection(); } setupConnection() { this.connection = createConnection( this.state.serverUrl, this.props.roomId ); this.connection.connect(); } destroyConnection() { this.connection.disconnect(); this.connection = null; } render() { return ( <> <label> URL del server:{' '} <input value={this.state.serverUrl} onChange={e => { this.setState({ serverUrl: e.target.value }); }} /> </label> <h1>Benvenuto nella room {this.props.roomId}!</h1> </> ); } }
Nota che in sviluppo, quando Strict Mode è attivo, React chiamerà componentDidMount, chiamerà immediatamente componentWillUnmount, e poi chiamerà di nuovo componentDidMount. Questo ti aiuta a notare se hai dimenticato di implementare componentWillUnmount o se la sua logica non “rispecchia” completamente ciò che fa componentDidMount.
Catturare errori di renderizzazione con un contenitore di errori
Per impostazione predefinita, se la tua applicazione lancia un errore durante la renderizzazione, React rimuoverà la sua UI dallo schermo. Per evitare questo, puoi avvolgere una parte della tua UI in un contenitore di errori. Un contenitore di errori è un componente speciale che ti permette di mostrare una UI di fallback invece della parte che è crashata — ad esempio, un messaggio di errore.
Per implementare un componente contenitore di errori, devi fornire static getDerivedStateFromError, che ti permette di aggiornare lo state in risposta a un errore e mostrare un messaggio di errore all’utente. Puoi anche implementare opzionalmente componentDidCatch per aggiungere logica extra, ad esempio per registrare l’errore in un servizio di analytics.
Con captureOwnerStack puoi includere l’Owner Stack durante lo sviluppo.
import * as React from 'react';
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
// Aggiorna lo state così la prossima renderizzazione mostrerà la UI di fallback.
return { hasError: true };
}
componentDidCatch(error, info) {
logErrorToMyService(
error,
// Esempio di "componentStack":
// in ComponentThatThrows (created by App)
// in ErrorBoundary (created by App)
// in div (created by App)
// in App
info.componentStack,
// Attenzione: `captureOwnerStack` non è disponibile in produzione.
React.captureOwnerStack(),
);
}
render() {
if (this.state.hasError) {
// Puoi renderizzare qualsiasi UI di fallback personalizzata
return this.props.fallback;
}
return this.props.children;
}
}Poi puoi avvolgere una parte del tuo albero di componenti con esso:
<ErrorBoundary fallback={<p>Qualcosa è andato storto</p>}>
<Profile />
</ErrorBoundary>Se Profile o un suo componente figlio lancia un errore, ErrorBoundary “catturerà” quell’errore, mostrerà una UI di fallback con il messaggio di errore che hai fornito e invierà un report di errore in produzione al tuo servizio di segnalazione errori.
Non devi avvolgere ogni componente in un contenitore di errori separato. Quando pensi alla granularità dei contenitori di errori, considera dove ha senso mostrare un messaggio di errore. Ad esempio, in un’app di messaggistica ha senso posizionare un contenitore di errori attorno all’elenco delle conversazioni. Ha senso anche posizionarne uno attorno a ogni singolo messaggio. Tuttavia, non avrebbe senso posizionare un contenitore di errori attorno a ogni avatar.
Alternatives
Migrare un componente semplice da classe a funzione
Di solito definirai i componenti come funzioni.
Ad esempio, supponiamo che tu stia convertendo questo componente classe Greeting in una funzione:
import { Component } from 'react'; class Greeting extends Component { render() { return <h1>Hello, {this.props.name}!</h1>; } } export default function App() { return ( <> <Greeting name="Sara" /> <Greeting name="Cahal" /> <Greeting name="Edite" /> </> ); }
Definisci una funzione chiamata Greeting. Qui sposterai il corpo della tua funzione render.
function Greeting() {
// ... sposta qui il codice dal metodo render ...
}Invece di this.props.name, definisci la prop name usando la sintassi di destructuring e leggila direttamente:
function Greeting({ name }) {
return <h1>Hello, {name}!</h1>;
}Ecco un esempio completo:
function Greeting({ name }) { return <h1>Hello, {name}!</h1>; } export default function App() { return ( <> <Greeting name="Sara" /> <Greeting name="Cahal" /> <Greeting name="Edite" /> </> ); }
Migrare un componente con state da classe a funzione
Supponiamo che tu stia convertendo questo componente classe Counter in una funzione:
import { Component } from 'react'; export default class Counter extends Component { state = { name: 'Taylor', age: 42, }; handleNameChange = (e) => { this.setState({ name: e.target.value }); } handleAgeChange = (e) => { this.setState({ age: this.state.age + 1 }); }; render() { return ( <> <input value={this.state.name} onChange={this.handleNameChange} /> <button onClick={this.handleAgeChange}> Incrementa età </button> <p>Ciao, {this.state.name}. Hai {this.state.age} anni.</p> </> ); } }
Inizia dichiarando una funzione con le necessarie variabili di state:
import { useState } from 'react';
function Counter() {
const [name, setName] = useState('Taylor');
const [age, setAge] = useState(42);
// ...Poi, converti i gestori di eventi:
function Counter() {
const [name, setName] = useState('Taylor');
const [age, setAge] = useState(42);
function handleNameChange(e) {
setName(e.target.value);
}
function handleAgeChange() {
setAge(age + 1);
}
// ...Infine, sostituisci tutti i riferimenti che iniziano con this con le variabili e le funzioni che hai definito nel tuo componente. Ad esempio, sostituisci this.state.age con age e this.handleNameChange con handleNameChange.
Ecco un componente completamente convertito:
import { useState } from 'react'; export default function Counter() { const [name, setName] = useState('Taylor'); const [age, setAge] = useState(42); function handleNameChange(e) { setName(e.target.value); } function handleAgeChange() { setAge(age + 1); } return ( <> <input value={name} onChange={handleNameChange} /> <button onClick={handleAgeChange}> Incrementa età </button> <p>Ciao, {name}. Hai {age} anni.</p> </> ) }
Migrare un componente con metodi del lifecycle da classe a funzione
Supponiamo che tu stia convertendo questo componente classe ChatRoom con metodi del lifecycle in una funzione:
import { Component } from 'react'; import { createConnection } from './chat.js'; export default class ChatRoom extends Component { state = { serverUrl: 'https://localhost:1234' }; componentDidMount() { this.setupConnection(); } componentDidUpdate(prevProps, prevState) { if ( this.props.roomId !== prevProps.roomId || this.state.serverUrl !== prevState.serverUrl ) { this.destroyConnection(); this.setupConnection(); } } componentWillUnmount() { this.destroyConnection(); } setupConnection() { this.connection = createConnection( this.state.serverUrl, this.props.roomId ); this.connection.connect(); } destroyConnection() { this.connection.disconnect(); this.connection = null; } render() { return ( <> <label> URL del server:{' '} <input value={this.state.serverUrl} onChange={e => { this.setState({ serverUrl: e.target.value }); }} /> </label> <h1>Benvenuto nella room {this.props.roomId}!</h1> </> ); } }
Per prima cosa, verifica che il tuo componentWillUnmount faccia l’opposto di componentDidMount. Nell’esempio sopra, è vero: disconnette la connessione che componentDidMount imposta. Se manca questa logica, aggiungila per prima.
Poi, verifica che il tuo metodo componentDidUpdate gestisca i cambiamenti di qualsiasi props e state che usi in componentDidMount. Nell’esempio sopra, componentDidMount chiama setupConnection che legge this.state.serverUrl e this.props.roomId. Ecco perché componentDidUpdate verifica se this.state.serverUrl e this.props.roomId sono cambiati e resetta la connessione se lo hanno fatto. Se la logica di componentDidUpdate manca o non gestisce i cambiamenti di tutte le props e lo state rilevanti, correggila per prima.
Nell’esempio sopra, la logica dentro i metodi del lifecycle collega il componente a un sistema esterno a React (un server chat). Per collegare un componente a un sistema esterno, descrivi questa logica come un singolo Effetto:
import { useState, useEffect } from 'react';
function ChatRoom({ roomId }) {
const [serverUrl, setServerUrl] = useState('https://localhost:1234');
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => {
connection.disconnect();
};
}, [serverUrl, roomId]);
// ...
}Questa chiamata a useEffect equivale alla logica nei metodi del lifecycle sopra. Se i tuoi metodi del lifecycle fanno più cose non correlate, suddividili in più Effetti indipendenti. Ecco un esempio completo con cui puoi sperimentare:
import { useState, useEffect } from 'react'; import { createConnection } from './chat.js'; export default function ChatRoom({ roomId }) { const [serverUrl, setServerUrl] = useState('https://localhost:1234'); useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => { connection.disconnect(); }; }, [roomId, serverUrl]); return ( <> <label> Server URL:{' '} <input value={serverUrl} onChange={e => setServerUrl(e.target.value)} /> </label> <h1>Benvenuto nella room {roomId}!</h1> </> ); }
Migrare un componente con context da classe a funzione
In questo esempio, i componenti classe Panel e Button leggono il context da this.context:
import { createContext, Component } from 'react'; const ThemeContext = createContext(null); class Panel extends Component { static contextType = ThemeContext; render() { const theme = this.context; const className = 'panel-' + theme; return ( <section className={className}> <h1>{this.props.title}</h1> {this.props.children} </section> ); } } class Button extends Component { static contextType = ThemeContext; render() { const theme = this.context; const className = 'button-' + theme; return ( <button className={className}> {this.props.children} </button> ); } } function Form() { return ( <Panel title="Welcome"> <Button>Sign up</Button> <Button>Log in</Button> </Panel> ); } export default function MyApp() { return ( <ThemeContext value="dark"> <Form /> </ThemeContext> ) }
Quando li converti in componenti funzione, sostituisci this.context con chiamate a useContext:
import { createContext, useContext } from 'react'; const ThemeContext = createContext(null); function Panel({ title, children }) { const theme = useContext(ThemeContext); const className = 'panel-' + theme; return ( <section className={className}> <h1>{title}</h1> {children} </section> ) } function Button({ children }) { const theme = useContext(ThemeContext); const className = 'button-' + theme; return ( <button className={className}> {children} </button> ); } function Form() { return ( <Panel title="Welcome"> <Button>Sign up</Button> <Button>Log in</Button> </Panel> ); } export default function MyApp() { return ( <ThemeContext value="dark"> <Form /> </ThemeContext> ) }