Ciclo Di Vita Di Un Componente React

Ciclo di Vita di un Componente

Nei  class component possiamo gestire il ciclo di vita di un componente React tramite l’override di alcuni metodi speciali.

Questi metodi possono essere divisi in metodi relativi al montaggio (mount) , all’aggiornamento (update) e allo smontaggio (unmount) del componente.

Il ciclo di vita  di un componente segue il seguente ordine:

  • Fase di Mounting
    • constructor()
    • componentWillMount
    • render()
    • componentDidMount()
  • Fase di Update
    • componentWillReceiveProps()
    • shouldComponentUpdate (): nel caso ritorni false,  i metodi successivi non verranno chiamati, e di conseguenza, neanche il metodo render
    • componentWillUpdate()
    • render()
    • componentDidUpdate()
  • Fase di Unmounting
    • componentWillUnmount()

Notare che i metodi che cominciano con will precedono un evento, mente con did  seguono un evento. Analizziamoli uno ad uno.

ComponentWillMount  (fase di mounting)

Questo metodo viene chiamato dopo il costruttore e prima del render. Non  può accedere agli elementi del DOM (perchè non ancora caricati) pero può modificare lo state. Può essere utilizzato per fare chiamate agli endpoint.

ComponentDidMount (fase di mounting)

In genere è usato per quelle operazioni che necessitano del DOM pronto. Chiamare setState in questo metodo darà vita ad un render. Può essere utilizzato anche per fare chiamate ad endpoint. 

ComponentWillReceiveProps (fase di update)

Questo metodo riceve in ingresso l’oggetto nextProps il quale contiene le props che stanno per arrivare al componente.

ShouldComponentUpdate (fase di update)

Il metodo shouldComponentUpdate riceve in input  gli oggetti nextProps e nextState. e ritorna un booleano. Se ritorna true, i metodi successivi (tra cui render) verranno chiamati. Altrimenti questa fase verrà bloccata in questo punto. Questo metodo dà la possibilità di bloccare il render o di attivarlo (ritornando true) solo al verificarsi di certe condizioni, scelte ovviamente da noi. 

ComponentWillUpdate (fase di update)

Il metodo componentWillUpdate riceve in ingresso nextProps e nextState. Può essere utilizzato per preparare il componente prima che avvenga l’aggiornamento dell’oggetto State o dell’oggetto Props.

ComponentDidUpdate (fase di update)

Il metodo componentDidUpdate riceve in ingresso prevProps e prevState.  E’ possibile fare modifiche al DOM. React suggerisce di sfruttare questo metodo per chiamate ad endpoint. 

ComponentWillUnmount (fase di unmounting)

Il metodo componentWillUnmount viene chiamato prima che il componente venga rimosso e distrutto.

Esempio di utilizzo dei lifecycle methods:

Supponiamo di voler creare un orologio che visualizzi l’orario a video. Avremo in questo caso un unico componente, chiamato Clock, con un’unica proprietà nello state, l’ora corrente (chiamata date). Un primo modo di farlo è il seguente:

function Clock(props) {
  return (
    <div>
      <h1>Ciao, mondo!</h1>
      <h2>Sono le {props.date.toLocaleTimeString()}.</h2>
    </div>
  );
}

function tick() {
  ReactDOM.render(
    <Clock date={new Date()} />,
    document.getElementById('root')
  );
}

setInterval(tick, 1000);

Provalo su CodePen

Il metodo javascript setInterval() consente di eseguire delle istruzioni di codice ogni tot millisecondi. 

Nel nostro caso, setinterval, ogni 1000 millisecondi, richiama la funzione tick, che a sua volta richiama il metodo render, passando in input il componente clock, che stampa l’ora corrente.

Tuttavia, manca un requisito fondamentale: il fatto che Clock imposti un timer ed aggiorni la propria UI ogni secondo dovrebbe essere un dettaglio implementativo di Clock. Idealmente, vorremmo scrivere il seguente codice una volta sola, ed ottenere che Clock si aggiorni da solo:

ReactDOM.render(
  <Clock />,
  document

Per fare ciò, abbiamo bisogno di aggiungere uno “stato” al componente Clock.

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  render() {
    return (
      <div>
        <h1>Ciao, mondo!</h1>
        <h2>Sono le {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

ReactDOM.render(
  <Clock />,
  document.getElementById('root')
);

Prova su CodePen

Il problema ora è che Clock non si aggiornerà ogni secondo ma mostrerà l’ora di creazione.

Per rimediare a questo problema, useremo i metodi di lifecycle della fase di mounting e unmounting.

Ogni volta che Clock  è renderizzato nel DOM per la prima volta (quindi è in fase di mounting), imposteremo un timer.

Analogamente, elimineremo il timer ogni volta che il DOM prodotto da Clock viene rimosso ( cioè nella fase di “unmounting” del componente).

Per ottenere questo, dobbiamo fare l’override dei metodi componentDidMount() e componentWillUnmount():

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  componentDidMount() {

  }

  componentWillUnmount() {

  }

  render() {
    return (
      <div>
        <h1>Ciao, mondo!</h1>
        <h2>Sono le {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

Nel metodo componentDidMount(), eseguito dopo che l’output del componente è stato renderizzato nel DOM, possiamo impostare un timer:

  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }

L’ID del timer può essere salvato direttamente in this. Nel metodo del componentWillUnmount() il timer TimerId viene, invece, eliminato:

  componentWillUnmount() {
    clearInterval(this.timerID);
  }

Infine, nel  metodo tick(), che verrà invocato dal componente Clock ogni secondo, aggiorneremo lo stato “date”:

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }

  componentWillUnmount() {
    clearInterval(this.timerID);
  }

  tick() {
    this.setState({
      date: new Date()
    });
  }

  render() {
    return (
      <div>
        <h1>Ciao, mondo!</h1>
        <h2>Sono le {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

ReactDOM.render(
  <Clock />,
  document.getElementById('root')
);

Prova su CodePen

In questo modo l’orologio scatta ogni secondo.

Ricapitolando, avremo che:

  1.  Viene passato a ReactDOM.render() e di conseguenza React invoca il costruttore del componente Clock. Nel costruttore viene inizializzato un oggetto (chiamato “date” ) appartenente a this.state in cui inserire l’ora corrente. Ogni volta che “date” viene aggiornato React invocherà il metodo render() del componente Clock.
  2. Quando l’output del metodo render di Clock viene inserito nel DOM, React invoca il metodo componentDidMount(). Al suo interno, il componente Clock chiede al browser di impostare un timer con cui invocare il metodo tick() del componente una volta al secondo.
  3. Ogni secondo, il browser invoca il metodo tick(). Al suo interno, viene aggiornato l’oggetto “date” dello stato con la nuova ora corrente. Grazie a questo aggiornamento, React invoca nuovamente il metodo render() e aggiorna il DOM di conseguenza.
  4. Se il componente Clock dovesse mai essere rimosso dal DOM, React invocherebbe il metodo componentWillUnmount() ed il timer verrebbe eliminato.Se il componente Clock dovesse mai essere rimosso dal DOM, React invocherebbe il metodo componentWillUnmount() ed il timer verrebbe eliminato.