React è una libreria Javascript open source utilizzata per lo sviluppo di interfacce utente. Trattandosi di una libreria (e non di un framework - come ad esempio Angular) è utilizzabile sia per la creazione di applicazioni from scratch, sia il potenziamento di progetti esistenti, integrando la libreria via CDN.

Sviluppata dal team di Facebook nel 2011 (allo scopo iniziale di gestire le news feed all’interno del social stesso), la libreria React è stata collaudata e distribuita a partire dal 2013.

Nel giro di qualche anno è diventata estremamente popolare e, insieme ad Angular e Vue, rappresenta oggi la scelta più gettonata per lo sviluppo di Web Application moderne. Vediamo quindi cos’è che rende React tanto affascinante.

React e la riusabilità dei componenti

React (così come Angular e Vue) ha un’architettura component-based. Nel caso in cui tu non sappia cosa sia, un componente è un blocco di codice autonomo e riutilizzabile che permette di organizzare l’applicazione con una struttura ad albero. 

Nell’immagine qui sopra, possiamo vedere come in una pagina basilare di un sito web si possano nascondere (almeno) 6 componenti. 

Sidebar, navbar, footer e content sono tutti componenti; ma anche le voci del menù e il form sono a loro volta dei componenti.

I benefici che questo approccio porta al mio sito web sono riassumibili in questo esempio: supponiamo che lo stesso form debba essere renderizzato in 8 pagine differenti e che, di punto in bianco, il cliente ci chieda con urgenza (?) di aggiungere tre campi al form. Essendo i componenti strutture indipendenti e autosufficienti, basterà aggiornare un unico file per accontentare il cliente.

I componenti da vicino e il concetto di state

In React esistono due tipi di componente, ma prima di poterli analizzare da vicino è necessario soffermarsi sul concetto di state.

Lo state è un particolare oggetto JavaScript che ha lo scopo di mantenere le informazioni di un componente; ogni componente è dunque descritto dalle proprietà del proprio oggetto state

React resta in ascolto dei cambiamenti dello state di ogni componente e, ogni qualvolta questo subisca delle modifiche, la visualizzazione del componente viene aggiornata.

Come si diceva, un componente React può essere implementato in due diversi modi:

  1. mediante classi, dando vita ai class components

  2. tramite funzioni JavaScript, dando vita ai functional o stateless components.

Un class component deve estendere la classe base React.Component e implementare il metodo render() che ritorna il codice JSX che renderizza la view del nostro componente. Trattandosi di una classe, un componente di questo tipo ha un proprio ciclo di vita e questo permette di sfruttare gli eventi del lifecycle di react e di mantenere uno stato interno dell’oggetto

Un componente implementato come functional component, è appunto una semplice funzione e pertanto non è adatto a gestire una logica complessa. A differenza del class component infatti non rende possibile la definizione di altri metodi oltre a render() e soprattutto non mantiene un proprio stato locale (da qui, l’alias stateless). 

Quest’ultima caratteristica ha una duplice ripercussione: 

  1. impedisce che il componente venga tenuto in considerazione durante il lazy-load e dunque migliora le performance dell’algoritmo;

  2. lo state (ricordiamo, inesistente) del componente dovrà essere gestito da un parent component rendendo un po’ più complessa lo scambio delle informazioni all’interno dell’applicazione.

Nonostante il precedente punto 2, è importante ricordare che il team di sviluppo di React incoraggia all’utilizzo dei componenti funzionali poiché presentano una serie di vantaggi, tra cui una migliore leggibilità del codice, una maggiore facilità di test, e performance più alte. L’unico “punto debole” che resta da fronteggiare è quello della difficoltà di comunicazione tra componenti stateless. Per ovviare, è possibile ricorrere a due tipi di soluzione: 

  1. L’utilizzo di Redux

  2. L’inclusione degli Hook (a partire dalla versioni 16.8 di React)

Più avanti descriveremo brevemente entrambi i concetti. Ma prima continuiamo ad analizzare i concetti chiave di React. 

JSX: l’unione fa la forza

React fa uso della sintassi JSX (JavaScript Syntax Extension), un’estensione di JavaScript che unisce codice e markup, permettendo di scrivere tag HTML (e eventualmente CSS) all’interno del JavaScript. 

In JSX, markup e logica convivono all’interno dello stesso blocco di codice e, per quanto possa inizialmente farvi rabbrividire, questo approccio facilita la scrittura dei react components che devono altrimenti essere creati con del codice JavaScript ben più verboso (mostrato nell’immagine qui sotto). 

Tale sintassi non è chiaramente interpretabile dal browser ed è pertanto necessaria una fase di transpilazione (tipicamente attuata dal compilatore Babel) che produrrà puro codice JavaScript.

Parliamo di performance: il Virtual DOM

Oggi i motori javascript utilizzati dai browser moderni sono altamente performanti e riescono a gestire applicazioni anche molto complesse. Ad ogni modo, la fase più critica in termini di performance resta sicuramente l’aggiornamento del DOM.

React fa fronte a questo possibile collo di bottiglia, ricorrendo all’utilizzo del virtual DOM, ovvero una rappresentazione astratta in memoria del DOM reale, creata in fase di mount

Il DOM virtuale viene aggiornato ogni qualvolta avvenga un cambiamento all’interno dell’applicazione (come ad esempio un cambio di state di un component) e un algoritmo detto compute diff compara l’attuale stato del DOM con quello precedente, aggiornando conseguentemente il DOM reale con le sole variazioni necessarie. 

Scalabilità: Flux e Redux

Partendo dal presupposto che React si basa sulla struttura a componenti, in tutta probabilità, più la nostra applicazione cresce, più saranno i componenti che la costituiranno (con annidamenti potenzialmente infiniti). 

Dunque, tanti più saranno i componenti, quanto più sarà oneroso condividere le informazioni (i vari state) dell’app in tutta l’applicazione, a maggior ragione se si tratta di componenti funzionali (che ricordiamo essere stateless). A questo proposito ci viene in aiuto un design pattern chiamato Flux (l’application structure che Facebook predilige per costruire applicazioni di tipo client-side) che supera il concetto di MVC per introdurre un’architettura di tipo state-management

React si approccia quindi allo state-management mediante l’utilizzo di Redux, un framework che implementa Flux e i suoi principi base. Tali principi possono essere riassunti nei seguenti tre concetti chiave: 

  • store: è l’oggetto che mantiene lo stato dell’intera applicazione

  • action: oggetti che inviano informazioni dall’applicazione allo store (gli unici autorizzati a modificarne lo stato)

  • reducer: funzioni pure che prendono in input lo stato dell’applicazione e una action e restituiscono una copia dello stato aggiornato rispetto al precedente.

Ogni componente dell’applicazione che si sottoscriva allo store sarà quindi notificato di ogni cambiamento di stato e potrà eventualmente aggiornarsi.

Uno sguardo a Luke. Hem.. agli Hook!

Il concetto di Hook viene introdotto in React a partire dalla versione 16.8 con lo scopo di risolvere una serie di difficoltà (di cui si parla ampiamente nella pagina ufficiale di React) emerse durante l’utilizzo della libreria. Una di queste, come si è visto nel paragrafo relativo ai componenti, è l’impossibilità di gestire lo stato nei functional components.

Vediamo brevemente l’hook principale o, quantomeno, colui che ci permette di gestire lo stato dei componenti: useState

Si prenda ad esempio il codice del functional component HelloIAMdev riportato qui sotto.

In riga 4 succede questo: il metodo useState prende in input un parametro che è il valore con cui inizializzare yourName e restituisce una tupla il cui il primo elemento è, appunto, il valore aggiornato della variabile di stato e il secondo è un metodo (setName), richiamabile ovunque, che serve per aggiornare il valore di questa variabile. 

In riga 17 all’onChange del campo di testo viene infatti invocato il metodo setName con il valore inserito dall’utente: la variabile yourName, e dunque lo stato del componente, risulterà aggiornato. 

Con questa piccola aggiunta, il componente funzionale diventa magicamente statefull, acquista potenza e scoraggia maggiormente all’utilizzo dei più prolissi class components.

Questo è soltanto uno degli hook che React mette a disposizione (useEffect, useContext ecc., sono hook altrettanto potenti). Con gli hook si apre infatti un capitolo estremamente vasto e se si desidera approfondire si consiglia di fare riferimento direttamente alla pagina ufficiale.

Conclusioni

Questa breve panoramica su React è solo un’infarinatura di ciò che questa potente libreria è in grado di offrire. Non esiste un criterio universale per decidere se adottare React piuttosto che una delle sue alternative, Angular o Vue. Pertanto, con questo articolo non si intende incitare all’utilizzo di questa libreria o promuoverla a discapito dei suoi “avversari”. Molti dei concetti di cui si è parlato sono comuni anche ad Angular e Vue e ognuno dei tre framework/librerie ha i propri punti di forza o debolezza (se debolezza si può definire). In un articolo che prossimamente pubblicheremo, metteremo a confronto questi tre protagonisti del web development e ne evidenzieremo differenze e analogie così da poter dare quantomeno un’idea sulla scelta da prendere a seconda del progetto che si deve iniziare.