back to top

Componenti React dinamici

Abbiamo ampiamente parlato dell’oggetto props che possiamo usare per passare diverse informazioni ai nostri componenti. In questo articolo introdurremo un secondo concetto fondamentale: l’oggetto state. Finora, infatti, non abbiamo potuto apprezzare in pieno le potenzialità di React e ci siamo limitati a vedere componenti configurabili ma statici. A partire da questo articolo, renderemo i nostri componenti dinamici e vedremo come sia possibile eseguire diverse azioni in seguito all’interazione dell’utente con il componente.

Class Component e oggetto State

Ancora una volta, React rende il tutto estremamente semplice. Ricordiamo che l’unica responsabilità dell’oggetto props, che è un oggetto di sola lettura, è quella di passare le informazioni da un componente ai componenti figli. A differenza dell’oggetto props, costituito da valori statici, l’oggetto state rappresenta un insieme di valori che è gestito e aggiornato dal componente in cui è incapsulato. Se per l’oggetto props, l’unica regola da ricordare era di non modificarne mai il suo valore o quello delle sue proprietà, per l’oggetto state dobbiamo tenere in mente che possiamo modificarlo solo attraverso l’uso della funzione setState(), ereditata da tutti i Class Component. Un’importante differenza, infatti, tra quest’ultimi e i Functional Component è che solo i primi possono avere uno stato interno. I Functional Component, al contrario, sono stateless perciò non potranno mai avere uno stato interno.

// Non aggiornare mai 'state' direttamente, React non aggiornerà il componente
this.state.counter = 1 // NO!

// Versione Corretta
this.setState({counter: 1}); // OK

Ogni volta che chiameremo la funzione setState(), React aggiornerà l’oggetto state con le nuove informazioni. Se poi passeremo le proprietà dell’oggetto state ai componenti figli tramite props, alla ricezione del nuovo valore, React aggiornerà anche tali componenti. Approfondiremo l’argomento quando parleremo del ciclo di vita dei Componenti.

L’oggetto state è dunque incapsulato all’interno di un componente che è l’unico ad avere il diritto e la responsabilità di modificarlo. Ogni componente non saprà mai se gli altri presentano uno stato interno o meno.

Nell’esempio sottostante vedremo come usare la funzione setState() per aggiornare un componente.

class Dado extends React.Component {
  constructor(props) {
    super(props);
    this.state = {numeroEstratto: 0};
  }
  randomNumber() {
    return Math.round(Math.random() * 5) + 1;
  }
  lanciaDado() {
    this.setState({numeroEstratto: this.randomNumber()});
  }
  render() {
    let valore;
    if (this.state.numeroEstratto === 0) {
      valore = <small>Lancia il dado cliccando <br /> sul pulsante sottostante</small>;
    }else{
      valore = <span>{this.state.numeroEstratto}</span>;
    }
    return (
      <div className="card" >
        <p className="card__number">{valore}</p>
        <button className="card__button" onClick={() => this.lanciaDado()} >Lancia il Dado</button>
      </div>
    )
  }
}

Per prima cosa creiamo un componente Dado. Nel costruttore usiamo il metodo super(props) per invocare il costruttore dell’oggetto padre e inizializzare correttamente il componente. Se non invochiamo il metodo super(props), non possiamo usare la keyword this all’interno del costruttore. Definiamo anche un oggetto state con una sola proprietà che useremo per tener traccia del numero estratto ad ogni lancio. Nella funzione render() mostriamo un messaggio iniziale se non è mai stato premuto il pulsante ‘Lancia il dado’; in caso contrario, verrà mostrato il numero estratto ad ogni lancio. Ogni volta che viene premuto il pulsante, viene invocata la funzione lanciaDado() che calcola un numero casuale compreso fra 1 e 6 e lo assegna a this.state.numeroEstratto tramite la funzione setState(). Trascuriamo per ora alcuni importanti dettagli in merito all’uso della keyword this all’interno dei componenti. Tratteremo l’argomento in maniera approfondita nei prossimi articoli.

gif animata dell'applicazione React lancio di un dado

Proprietà della funzione setState()

La funzione setState() presenta alcune caratteristiche che è bene tenere in considerazione durante lo sviluppo delle nostre applicazioni.

React potrebbe raggruppare più chiamate della funzione setState() ed eseguire l’aggiornamento dell’oggetto state una volta sola. L’aggiornamento degli oggetti state e props può avvenire in maniera asincrona e per questo motivo, per calcolare lo stato futuro di un componente, usando i valori attuali dell’oggetto state e props, dovremmo usare un’altra versione di setState() che riceve come unico argomento una funzione. A questa vengono passati due argomenti, ovvero i valori correnti degli oggetti state e props.

/* Facciamo riferimento all'esempio presente nella documentazione ufficiale
*
*  Supponiamo che al momento di invocare this.setState,
*  un componente presenti il seguente stato:
*  
*  this.state = {counter: 1}
*
* Quando verrà chiamata la funzione setState, prevState.counter
* sarà uguale a 1 
*/

this.setState((prevState, props) => ({
    counter: prevState.counter + props.increment
}));

Inoltre se un componente presenta un oggetto state con più coppie chiave-valore, volendo aggiornare una sola di queste, basterà passare alla funzione setState() un oggetto con i soli valori che si intendono modificare. React provvederà a combinare il nuovo oggetto passato con i valori attuali dell’oggetto state

class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      proprieta1: "valore1",
      proprieta2: "valore2",
      proprieta3: [1,2,3,4,5]
    }
  }
  // ... resto del componente
}

// ... 
// ...

// Se a un certo punto invochiamo
this.setState({proprieta1: "nuovoValore1"})

// Dopo aver chiamato la funzione setState(), avremo il seguente oggetto state
this.state = {
  proprieta1: "nuovoValore1", // verrà aggiornata solo proprieta1
  proprieta2: "valore2",
  proprieta3: [1,2,3,4,5]
}

Flusso unidirezionale di dati

Al contrario di altri framework, React introduce il concetto di flusso di dati unidirezionale (Unidirectional Data Flow). Non tutti i componenti sono uguali all’interno della nostra applicazione. Non tutti i componenti dovranno avere uno stato interno, al contrario è consigliato costruire componenti senza stato (stateless). Possiamo vedere la nostra applicazione come una gerarchia di componenti. Solitamente avremo qualche componente ai vertici che sarà responsabile di mantenere lo stato della nostra applicazione e passerà le informazioni giù ai componenti figli tramite props. Possiamo immaginare il flusso di informazioni come una cascata.

Definiamo dunque un oggetto, contentente le informazioni dinamiche della nostra applicazione. Non faranno parte di tale oggetto le informazioni dinamiche derivabili o calcolabili a partire da altre. Questo oggetto costituisce lo stato dell’intera applicazione. Fatto ciò, dovremo affidare a un componente il compito di mantenere e modificare tale oggetto. Le informazioni mantenute in esso verranno poi passate ai componenti figli mediante l’uso dell’oggetto props.

Vediamo rapidamente un esempio pratico per capire meglio quanto appena descritto. Supponiamo di avere un’applicazione Rubrica con una serie di contatti. È possibile cercare tra i contatti tramite un campo di ricerca. Ogni volta che digiteremo un carattere nel campo di ricerca, verrà filtrata la lista dei contatti in base al testo digitato.

Applicazione React Rubrica di Supereroi

All’interno della nostra applicazione, l’unica informazione dinamica, che cambia in seguito all’interazione dell’utente e non può essere derivata da niente altro, è il testo che digitiamo all’interno del campo di ricerca. La lista dei contatti sarà invece passata attraverso l’oggetto props alla nostra applicazione. In un’applicazione reale potrebbe capitare di dovere scaricare da un server la lista aggiornata dei contatti, ma anche in questo caso sarà passata al componente più esterno App attraverso l’oggetto props. I due componenti che necessiteranno di usare il testo digitato saranno SearchBar e ContactList. Quest’ultimo lo utilizzerà per filtrare e mostrare una lista aggiornata dei contatti.

L’oggetto state iniziale della nostra applicazione sarà quindi {campoDiRicerca: ”}. Dobbiamo determinare qual è il miglior candidato fra i nostri componenti che si occuperà di mantenere al suo interno tale oggetto. Sarà questo componente l’unico ad avere la responsabilità di aggiornare l’oggetto state attraverso l’invocazione della funzione setState().

I due componenti SearchBar e ContactList hanno bisogno di usare il testo digitato nel campo di ricerca il quale rappresenta l’unica informazione dinamica della nostra applicazione. Entrambi sono racchiusi all’interno del componente App che è quindi il candidato ideale per mantenere l’oggetto state. Il componente App invocherà il metodo setState() per aggiornare il valore di state.campoDiRicerca e passerà il nuovo valore ai componenti figli attraverso l’oggetto props. Quando questi riceveranno il nuovo valore, verrà invocata la loro funzione render() che provvederà al loro aggiornamento.

Schema di funzionamento componenti React

Riprenderemo l’esempio appena discusso nei prossimi articoli. A partire dal prossimo, vedremo come creare strutture più complesse e annidare i vari componenti.

Pubblicità