KNOWLEDGE BASE

Knowledge Base
1Backup
Acronis
Antivirus
Email
Firewall
GFI Software
Mail
Monitoring
N-Able
Sicurezza
TSPlus
Diventa Autore per CoreTech | Scopri di più

Vai al Video

Introduzione a React

di Andrea Chiarelli

Tra le librerie utilizzate nello sviluppo di Single Page Applications spicca React.js, che è un valido supporto allo sviluppo tramite il linguaggio JavaScript.
In questo tutorial andremo a dare un'occhiata agli elementi di base per capire di cosa si tratta e come poter programmare utilizzando questa libreria. Poi vedremo un po’ di codice, come si definisce un componente e come i componenti possono passare i dati tra di loro e come possiamo gestire lo stato dei componenti.
Vedremo l’approccio alla progettazione di interfacce grafiche, l’uso di create-react-app per il setup di un’applicazione ecc.

Che cos’è React

React.js è una libreria JavaScript per la creazione di interfacce utente componibili, ossia formate da “componenti”; un componente di React.js è un elemento che contribuisce alla creazione dell’interfaccia utente. I componenti React hanno la capacità di presentare dati che cambiano nel tempo.
React implementa la parte View dei più comuni design pattern di presentazione. React è una libreria attualmente elemento fondamentale delle App. L’idea che sta alla base è creare pezzettini di interfaccia per poi montarli insieme ed avere così un’interfaccia organica. Quindi il componente è l’elemento essenziale che consente di costruire un’interfaccia grafica.

I componenti hanno una capacità intrinseca che è quella di trattare i dati in maniera automatica, cioè di renderizzare le informazioni che mostrano a video in maniera automatica; poi vedremo cosa intendiamo per visualizzazione automatica.
In particolare dobbiamo precisare che React implementa la parte clou dei più comuni design pattern di presentazione come ad esempio Model View controller e Model View viewmodel. Questo è per puntualizzare su una delle discussioni più in voga, che cercano di confrontare framework e librerie che hanno scopi diversi: una tra tutte è mettere a confronto Angular con React. Mentre Angular è un framework che si occupa di creare interfacce grafiche, ma anche di supportare lo sviluppo quasi a 360°, React è una libreria che si occupa semplicemente della parte view, quindi ha un obiettivo molto più limitato rispetto ad Angular, quindi il confronto non ha senso, se non quello di fuorviare lo sviluppatore.

PROGETTAZIONE DI INTERFACCE GRAFICHE

Cominciamo a vedere l’approccio che ci può tornare comodo per progettare delle interfacce grafiche. Un’interfaccia grafica, dal punto di vista di React, è un insieme di componenti.
Per aiutarvi a capire cos'è un componente in pratica, nell’immagine seguente proponiamo una schermata di YouTube nella quale abbiamo evidenziato alcuni elementi in rosso: i box intorno ai vari elementi rappresentano dei componenti.

Vedete un contenitore esterno che rappresenta l’intera pagina e al suo interno abbiamo:

  • la barra di ricerca, che è anche un componente;
  • il menu, che è un altro componente;
  • l’area principale, che è un altro componente.

Come potete vedere dall’immagine seguente, i componenti possono contenere altri componenti: l’area principale contiene i link con la sintesi dei video.

Naturalmente possiamo andare ancora avanti, cioè possiamo individuare elementi all’interno dell'area principale della nostra pagina e individuare altri componenti.
Viene quindi spontaneo il dubbio di quando ci possiamo fermare. In realtà non c’è una risposta precisa, perché la granularità (cioè la scomposizione) cui vogliamo arrivare dipende dal tipo di componente e dall’uso che dobbiamo farne.
In generale diciamo che un componente dovrebbe avere un unico scopo e possibilmente dovrebbe poter essere riutilizzato all’interno della stessa applicazione o di altre applicazioni.

Quindi individuare quando dobbiamo costruire un componente fa parte un po’ dell’esperienza personale e dipende anche un po’ dal buon senso.

La suddivisione che abbiamo visto prima delle varie parti da pagina la possiamo pensare anche come una struttura ad albero, dove il componente di più alto livello, cioè il genitore di quest’albero, è il componente che contiene gli altri gli altri componenti, come mostra l’immagine seguente, che sintetizza il concetto di granularità.

Quindi abbiamo una gerarchia dove in ogni nodo è presente un componente che può contenere altri componenti, che a loro volta possiamo altri componenti.
Spiegheremo più avanti in che modo i componenti comunicano tra di loro.

Setup di un’applicazione con React: la create-react-app

Passiamo ora a introdurre un tool di React che ci consente di creare in maniera abbastanza semplice un’applicazione: si tratta di create-react-app, il quale è un’interfaccia a riga di comando (CLI) che consente di fare il setup di un’applicazione React senza bisogno di complesse configurazioni d’ambiente.
Reat create-react-app è un comando che presuppone la presenza di Node.js sulla propria macchina, quindi è una Command Line Interface che crea l’ambiente di sviluppo dell’applicazione; per installarla utilizziamo il comando:

npm install -g create-react-app

che permette di scaricare dal repository npm il tool e di installarlo sulla propria macchina. Dopo aver installato il componente possiamo verificare che sia correttamente installato lanciando questo comando:

create-react-app --version

che consente di verificare la versione corrente. Infine con il comando seguente:

create-react-app hello-react


stabiliamo il nome che vogliamo dare alla nostra applicazione e con lo stesso andiamo a creare una cartella con lo stesso nome (in questo caso hello-react) nella quale vengono automaticamente inseriti gli elementi di base dell’applicazione React. All'interno avremo una serie di file; nell’immagine seguente vediamo direttamente su file-system l’insieme dei file che sono stati creati per un esempio di applicazione di applicazione minimale.

All’interno abbiamo tre cartelle che rappresentano insiemi dei moduli: node_modules è l’insieme dei moduli di Node.js utilizzati dal nostro ambiente di sviluppo. Quello che ci interessa in particolare è la cartella src, all'interno del quale sono contenuti i file JavaScript e tutto quello che ci occorre per creare la nostra applicazione. Abbiamo anche la cartella public.

Se lanciamo, dall'interno della cartella in cui è contenuta nostra applicazione, il comando:

npm start

viene eseguita l’applicazione e avviato il browser, che ci presenterà l'applicazione minima che è stata generata da React.
Questo ci evita di dover creare tutto un ambiente utilizzando una serie di tool come transpiler, bundle e altri tool del genere che servono per lo sviluppo moderno, per così dire, di JavaScript, quindi utilizzando questo tool abbiamo già tutto e gratis, il che ci consente di concentrarci semplicemente sullo sviluppo del codice senza bisogno di perdersi nei dettagli del setup dell’ambiente di sviluppo.

Definizione di un componente

Ora andiamo a vedere in dettaglio come possiamo scrivere il codice utilizzando la libreria. Un componente in realtà non è altro che una classe JavaScript che estende la classe component() di React. Quindi, come vedete, nella porzione di codice che segue abbiamo creato un modulo JavaScript dove abbiamo importato React dal modulo React stesso e abbiamo implementato la classe catalog che estende la classe react component. All’interno di questa classe abbiamo un unico metodo, chiamato render(), che restituisce del markup.

import React from 'react';

class Catalog extends React.Component {

  render() {

    return

Catalog

;

  }

}

export default Catalog;

Questo codice praticamente sta definendo un componente catalogo che noi definiamo all’interno di un file e possiamo utilizzare all’interno di un altro componente.

Il metodo render()

Ogni componente deve avere obbligatoriamente il metodo render (ogni componente React deve implementarlo); il metodo render è quello che definisce l’output del componente. Quello che abbiamo visto prima (return) praticamente è il codice che verrà realizzato per creare l’HTML interpretato dal browser.

Il metodo deve restituire un solo elemento React, cioè un singolo elemento di markup con eventuali elementi annidati. Inoltre deve essere una funzione pura, cioè non deve modificare lo stato interno del componente.
Ancora, il metodo render non deve interagire direttamente con il browser, cioè non deve contenere istruzioni che accedono al DOM.
Diciamo che in linea di massima usando React raramente avremo bisogno di accedere direttamente al DOM, perché il DOM del browser viene gestito in maniera abbastanza dal runtime di React, quindi se in qualche situazione abbiamo bisogno di accedere al DOM significa che stiamo facendo qualcosa di veramente avanzato o forse non stiamo usando l’approccio corretto nell’uso di react.


Utilizzo di un componente e uso di JSX

Bene, una volta abbiamo definito un componente vediamo come possiamo utilizzarlo all'interno di un altro componente: in questo caso abbiamo il componente App che vuole utilizzare il componente catalogo che abbiamo definito prima.
Quindi per prima cosa importiamo tramite import Catalog from './Catalog'; il catalogo dal modo che avevamo creato e utilizzeremo all’interno del markup da un tag che ha lo stesso nome della classe che abbiamo definito nella precedente.
Quindi che vedete in fondo alla porzione di codice seguente fa riferimento al componente creato precedentemente, pertanto in realtà è come se quando creiamo un componente è come se avessimo creato un elemento di markup che ha il nome della classe e possiamo utilizzarlo all’interno del markup di un altro componente.

import React, { Component } from 'react';

import './App.css';

import Catalog from './Catalog';

class App extends Component {

  render() {

    return (

     

 

       

         

The Catalog App

       

        <Catalog />

     

    );

  }

}

export default App;


Il markup che abbiamo visto finora sembra un po’ strano perché a stretto rigore non sarebbe JavaScript. In realtà quello che vediamo è JSX, cioè è un estensione di JavaScript con espressioni XML che ci consente di semplificare la creazione del DOM; in pratica noi è come se scrivessimo HTML all’interno del codice JavaScript e poi c’è un pre-processore che analizzerà questo codice XML e genererà gli elementi del DOM in maniera opportuna.

Quindi JSX estende JavaScript con espressioni XML per semplificare la creazione di elementi HTML all’interno del codice JavaScript.

Naturalmente un’espressione JSX non è HTML, quindi va rispettata una serie di regole; prima di tutto, trattandosi di XML devono essere rispettate le regole di base dello stesso, tra cui quella che i nomi dei dei tag devono essere in minuscolo. Poi come abbiamo visto prima un’espressione di JSX deve avere un unico elemento di markup; in esso possono essere contenuti più elementi, però l’elemento contenitore deve essere unico.

Vediamo dunque un primo esempio:

Catalog

questa stringa è valida, ossia è un esempio corretto di espressione JSX.
Invece quella seguente è un’espressione errata:

Catalog

 

Possiamo utilizzare espressioni GSX all’interno di JavaScript come se fossero delle normali espressioni, quindi possiamo assegnarle a una variabile come nell’esempio di codice che segue, dove abbiamo definito la variabile output e le abbiamo assegnato l’espressione JSX, poi a quel punto restituiamo la variabile output utilizzando l’istruzione let output.

 

 

import React from 'react';

import './Catalog.css';

class Catalog extends React.Component {

  render() {

    let output =

 

Catalog;

    return output;

  }

}

export default Catalog;

Allo stesso modo possiamo utilizzare espressioni JavaScript all’interno di markup JSX: nel caso abbiamo del codice seguente abbiamo una variabile title cui abbiamo assegnato una stringa e utilizziamo questa variabile all’interno del markup restituito da render.

 

import React from 'react';

import './Catalog.css';

class Catalog extends React.Component {

  render() {

    let title = "Catalog";

    return

{title}

;

  }

}

export default Catalog;

In questo caso la variabile viene messa tra parentesi graffe. Naturalmente questo è un caso semplice in cui alla variabile è stata assegnata una stringa, ma in realtà possiamo assegnare alla variabile un’espressione complessa quanto ci pare.

Ricordate che le restrizioni imposte da JSX sono principalmente tre:

  • tutti i tag HTML devono essere scritti in minuscolo; il motivo di questo è che stiamo lavorando con dell’XML;
  • al posto dell’attributo class dobbiamo utilizzare classname;
  • al posto dell’attributo for dobbiamo utilizzare HTML for.

Il motivo di queste due ultime restrizioni è che servono a evitare conflitti con le parole chiave di JavaScript Class e For.

Passaggio dei dati tra componenti

Qualche paragrafo indietro si è accennato al fatto che i componenti possono scambiarsi dati tra loro. Ora è giunto il momento di spiegare bene cosa significa.
Quando bisogna avere componenti che contengono altri componenti abbiamo necessità di passare dei dati da un componente all’altro; il passaggio dati tra un componente padre e componenti figli il passaggio viene fatto in maniera abbastanza semplice aggiungendo degli attributi al tag che identifica il componente in questione.
Quindi se abbiamo definito il componente product e lo usiamo all’interno del markup di un altro componente, se vogliamo passare dei parametri dell’informazione al nostro componente creeremo un attributo item. Nel caso proposto qui di seguito:

item={product}/>

Banner

abbiamo creato l’attributo item e passiamo tra parentesi graffe la variabile che contiene il parametro da passare al componente stesso.

Banner

All’interno del componente figlio utilizzeremo gli attributi tramite la proprietà props, quindi ogni componente ha una proprietà props. A queste queste proprietà vengono agganciati tutti gli eventuali attributi che vengono definiti a livello di markup quando si usa il componente, quindi nel caso proposto accediamo all’attributo item e in particolare, supponendo che l'attributo item sia un oggetto che ha le proprietà name e description, utilizziamo la proprietà name e la description per il markup del nostro componente.

 

 

class Product extends React.Component {

  render() {

    return

 

       

{this.props.item.name}

       

{this.props.item.description}

      ;

  }

}

Quindi ci serviamo della proprietà props per accedere ai dati passati dal componente padre.

Andiamo ora a definire il concetto di Stato per i componenti di React: il concetto di stato rappresenta in generale quell’insieme di informazioni che variano nel tempo, cioè un componente ha uno stato quando gli abbiamo passato delle informazioni ma queste informazioni possono essere modificate per l’intervento dell’utente (per interazione con l’utente) oppure perché abbiamo fatto una chiamata Ajax verso il server. Quindi quando abbiamo caricato dei dati e queste informazioni vengono modificate.
Dunque, lo stato dei componenti React è una proprietà (state) che contiene dati che variano nel tempo.
Lo stato dei componenti di React è rappresentato dalla proprietà state; i componenti che presentano dati che variano nel tempo sono detti stateful.
In linea di massima è bene ridurre al minimo il numero di componenti stateful, perché i componenti che non hanno delle informazioni al loro interno sono più semplici da testare, cioè i componenti senza stato si comportano un po’ come delle funzioni che ricevono dell’input ed hanno sempre lo stesso output, invece componenti con con lo stato gestito da un componente stateful può dipendere dallo stato che viene gestito internamente, quindi non è semplice creare dei test.

Per informare un componente che lo stato è cambiato usiamo il metodo setState(). Quindi quando cambia lo stato di un componente utilizzeremo il metodo setstate, che automaticamente e in maniera implicita causa l’esecuzione del metodo render() che aggiorna automaticamente l’interfaccia grafica.

Passiamo a chiarire questi concetti con un esempio di codice: nel listato che segue abbiamo la classe productlist e quindi l’implementazione del componente productlist; nel costruttore definiamo la proprietà state, ossia il valore dello stato di questo componente come un oggetto che contiene la proprietà product e inizialmente ha un array vuoto. Subito dopo vediamo l’esecuzione di fetch.

class ProductList extends React.Component {
constructor() {
super();
this.state = { products: [] };
fetch("products.json")
.then(response => response.json())
.then(json => {this.setState({products: json})})
.catch(error => console.log(error));
}
...
}

Per chi non lo sapesse, fetch è il successore di XML HTTP Request, ossia l’implementazione delle chiamate nelle versioni più recenti di JavaScript; nel caso specifico, fetch effettua una chiamata al server chiedendo un elenco di prodotti, in questo caso. Naturalmente è una chiamata asincrona, quindi quando creiamo il componente gli diamo uno stato iniziale che è un array vuoto di prodotti e fetch esegue la chiamata al server, quindi quando riceve la risposta da parte del server utilizzeremo setstate per cambiare lo stato corrente e dopo andremo a eseguire setstate e a specificare qual è il nuovo stato. In questo caso il nuovo stato è dato dall’oggetto che ha la proprietà products; il valore della proprietà product è rappresentato dal valore del JSON restituito da setstate (.then(json => {this.setState({products: json})}).
Notate che stiamo dando per scontato che il server ci restituisca un array di oggetti che rappresentano i prodotti.

In questo esempio applicativo, chiamando setstate stiamo chiedendo implicitamente al componente di eseguire il proprio metodo render() e quindi di aggiornare l’interfaccia; in pratica quello che otterremo è una propagazione dei dati, cioè quando ci troviamo con un’interfaccia complessa, dove un componente contiene altri componenti l’aggiornamento dello stato di un componente può creare una reazione a catena. Da qui deriva il nome React, perché infatti la modifica dello stato di un componente consente di avviare automaticamente il rendering del proprio markup, ossia della propria area di competenza all’interno dell’interfaccia grafica, ma allo stesso tempo se ci sono dei componenti figli vengono automaticamente aggiornate le props dei figli e automaticamente vengono riaggiornate anche le aree di competenza dei vari componenti. In questo modo un’interfaccia viene automaticamente aggiornata e quindi in maniera efficace perché React aggiorna selettivamente soltanto i componenti che hanno realmente una modifica all’interno del proprio stato; quindi se facciamo la modifica a un valore dello stato di un componente ma quel valore non viene cambiato, il componente interessato a quella proprietà non verrà aggiornato, verranno aggiornati soltanto quei componenti che hanno effettivamente una modifica nel proprio stato. L’immagine seguente schematizza la propagazione unidirezionale dei dati verso i componenti figli eseguita durante l’aggiornamento conseguente al rendering.

Gestione semplice e gestione indiretta degli eventi

Passiamo ora al concetto di gestione degli eventi: una gestione semplice degli eventi è quella che consente di definire dei metodi all’interno della classe che definisce il componente, come nel caso proposto dall’esempio di codice seguente, dove showPrice si limita semplicemente a visualizzare una certa informazione (il prezzo, in questo caso) dell’item e la presenza di attributi che consentono di eseguire il metodo che abbiamo appena definito.

import React from 'react';
class Product extends React.Component {
showPrice() {
alert(this.props.item.price);
}
render() {
return

  • this.showPrice()}>


Banner

 

{this.props.item.name}


{this.props.item.description}


;
}
}
export default Product;

In questo esempio vediamo che per il componente product, nel markup, viene restituito dal suo render() un attributo onclick; se ci fate caso, esso non è esattamente onclick dell’HTML, dove praticamente l’attributo onclick è tutto in minuscolo. Qui invece abbiamo onclick con la sola C maiuscola, il che significa che è un attributo speciale che viene intercettato da React e gestito in maniera opportuna.
In linea di massima la regola generale per individuare qual è l'attributo da utilizzare all’interno di React per gestire gli eventi fa riferimento all’attributo HTML, quindi si scrive con l’iniziale maiuscola il nome che segue on: quindi avremo onClick, onSum ecc. C’è da considerare tale piccola differenza sintattica.

L’esempio di gestione proposto è una forma abbastanza semplice di gestione degli eventi; una gestione più complessa è quella che consente di intercettare delle interazioni utente che richiedono la modifica di stato del componente padre. Facciamo un esempio grafico aiutandoci con l’immagine seguente, che schematizza la gestione indiretta degli eventi.

Supponiamo di avere lo stato iniziale del componente padre (state) i cui valori sono propagati ai figli tramite le props e imponiamo che si verifichi un’interazione dell’utente con uno dei nodi finali di questa struttura ad albero: per esempio uno di questi nodi potrebbe essere un pulsante, quindi l’utente interagisce col pulsante nella pagina web.

Vogliamo ora che lo stato del componente di più alto livello (padre) venga modificato dall’intervento su un componente di livello inferiore, quale è il pulsante; ebbene, nella gestione vista sinora non è ammesso, perché le modifiche negli stati seguono la gerarchia da padre a figli e non viceversa.

Banner

L’unico modo per ottenere ciò è abilitare setstate sul componente padre, cioè, in pratica dovremmo eseguire setstate sul componente padre; l’approccio da adottare esula dagli scopi di questo tutorial perché spiegarlo richiederebbe molto spazio. Diciamo che concettualmente significa che il componente padre deve passare tramite props anche un metodo che consente di modificare il proprio stato; avremo quindi un metodo passato tramite props che va reso disponibile dal nostro pulsante quando l’utente interagisce con il pulsante in realtà stai eseguendo un metodo che è il metodo del componente padre.

Approfondimenti

Bene, quello che abbiamo visto fino a ora costituisce i principi di base di React, ma ci sono altri argomenti che andrebbero approfonditi e che in questa sede non è possibile snocciolare; vi diamo però delle dritte per approfondirli autonomamente attingendo alla documentazione ufficiale e non reperibile sul web.

Tra questi argomenti suggeriamo:

  • Modifica dello stato dei componenti padre;
  • Ciclo di vita dei componenti (ComponentWillMount, ComponentDidMount, …);
  • PropTypes (controllo dei tipi di dato);
  • Routing (React Router);
  • Server-side rendering (ReactDOMServer).

Quanto al ciclo di vita dei componenti è la gestione di eventi che sono legati alla creazione di un componente, al caricamento nel DOM e così via.

PropTypes è un meccanismo offerto da React per avere un controllo dei tipi di dato, per cui possiamo definire delle proprietà e stabilire che certe proprietà accettino soltanto certi tipi di dato, come ad esempio stringhe o numeri o anche espressioni regolari.

Altro argomento interessante da approfondire nella creazione di applicazioni web lato front-end abbastanza evolute è l’utilizzo del routing lato front-end: in React abbiamo la libreria React Router che ci consente di mappare pool a componenti React.

Un ultimo argomento da approfondire è quello legato e la possibilità di avere il render lato server: normalmente il rendering di un componente React avviene sul client, perché è tutto codice JavaScript che viene eseguito su browser. Ma in situazioni particolari di efficienza oppure per questione di SEO (ottimizzazione per i motori di ricerca) potremmo desiderare di ottenere il rendering su server in modo che il browser ottenga direttamente l’HTML.
Questo è possibile tramite dei componenti particolari come ReactDOMServer, che può essere eseguito all’interno di Node.js e quindi su server per fare il rendering su server, cosicché al browser arrivi direttamente l’HTML.

Per gli approfondimenti dal web vi forniamo i seguenti riferimenti:

  • sito ufficiale https://reactjs.org/;
  • Thinking in React (https://reactjs.org/docs/thinking-in-react.html);
  • Tutorial: Intro to React (https://reactjs.org/tutorial/tutorial.html).