Passaggio all'ora legale 31 marzo 2019 02:0003:00 sposta avanti l'orologio di 1 ora (si dorme 1 ora in meno)
Continuando dall'esempio precedente vediamo come gestire lo stato di un componente, realizziamo un semplice orologio.
Il seguente esempio visualizza l'ora attuale:
class Clock extends React.Component {
  //aggiungo lo stato locale al componente
  constructor(props) {
    super(props);
    //creo l'oggetto che rappresenta lo stato del componente
    this.state = {date: new Date()};
  }
  //nessuna virgola di terminazione
  render() {
    return (
      <div>
        <h1>Orologio</h1>
        <h2>sono le {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

function tick() {
  ReactDOM.render(
    <Clock />,
    document.getElementById('root')
  );
}
//la data non cambia ad ogni richiamo (1s)
setInterval(tick, 1000);
per funzionare deve essere utilizzato la base html dell'esempio precedente
La prima cosa da notare è che l'oggetto è stato creato tramite la keyword class ed estende React.Component mentre nell'esempio precedente avevo usato function.
Nel costruttore dichiaro l'oggetto che manterrà lo stato this.state e nel metodo render ritorno l'html che rappresenta il componente.

Eseguendo questo esempio si nota subito che nonostante la funzione tick venga richiamata ogni secondo da setInterval la data non cambia. Questo perchè non abbiamo notificato a React che lo stato è cambiato.

Per visualizzare l'ora aggiornata dobbiamo modificare il codice e utilizzare il metodo this.setState per notificare il cambiamento che, a sua volta, scatena l'aggiornamento del componente, questa è la nuova versione:
class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {   //this.state has a special meaning
      date: new Date(),
      propTemp: 1 // non usato, non viene modificato da setState
    };
  }

  componentDidMount() {
    this.timerID = setInterval( 
      () => this.tick(),  // funzione anonima che richiama "tick"
      1000  // 1 secondo
    );
  }

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

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

  render() {
    return (
      <div>
        <h1>Orologio</h1>
        <h2>sono le {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

ReactDOM.render(
  <Clock />,
  document.getElementById('root')
);
in questo esempio ho introdotto un po' di cose nuove:
  • l'oggetto è stato creato tramite la keyword class (ES6)
  • la classe deve estendere (extends) l'oggetto React.Component
  • al costruttore deve essere passato l'oggetto props che conterrà gli eventuali valori assegnati agli attributi del tag dell'html
  • il costruttore deve sempre richiamare il metodo super(props)
  • this.state: mantiene lo stato del componente ed ha un significato speciale per React
  • componentDidMount: eseguito dopo che è stato invocato render e dopo che il DOM è stato aggiornato
  • componentWillUnmount: invocato quando il componente è rimosso dal DOM
  • this.setState: per notificare il cambiamento dello stato e scatenare il rendering (solo le parti modificate vengono aggiornate nel DOM)
  • la funzione tick è un metodo dell'oggetto Clock e non necessita della keyword function
inoltre l'oggetto state deve essere considerato immutabile, quindi non va mai modificato ma sempre ricostruito, questo permette a React di essere più efficente nell'individuare i cambiamenti.

Le cose di cui ricordarsi sono:
  • non modificare mai lo stato del componente direttamente, è ammesso solo nel costruttore, usare this.setState
  • l'aggiornamento dello stato può essere asincrono, per fare aggiornamenti multipli usare
    this.setState( (prevState, props) => {
    return { counter: prevState.counter + props.increment };
    });
  • gli aggiornamenti dello stato vengono combinati (merge) con i valori esistenti, questo vuol dire che posso aggiornare anche una sola proprietà non necessariamente tutto l'oggetto (se la proprietà modificata è un oggetto va passato un nuovo oggetto modificato)
  • un componente può passare lo stato a un componente "interno", il componente interno non deve sapere da dove arriva lo stato. Viene definita top-down o unidirectional data flow
  • lo stato va mentenuto in un unico punto, tipicamente il componente root della gerarchia

Vedi anche Components and Props, State and Lifecycle e React come funziona - Gestire gli eventi