Nella lezione precedente abbiamo analizzato le caratteristiche del Virtual DOM, il sistema con cui React astrae il DOM reale per rappresentare gli elementi dell'interfaccia utente e, a fronte di un evento, determinare come debba essere aggiornata applicando il minor numero possibile di modifiche agli elementi della pagina.
Ma quali sono le tipologie di oggetti che costituiscono internamente il Virtual DOM?
I "mattoncini" del Virtual DOM
Analogamente al DOM naturale, anche il Virtual DOM è composto da nodi che, organizzati gerarchicamente, rappresentano la struttura della pagina vista da React, e ciascuno di questi – giusto per iniziare a definire qualche termine tecnico – è chiamato ReactNode.
Una sequenza di più nodi, ovvero un array di ReactNode, si identifica con il termine ReactFragment.
In realtà, ReactNode potrebbe essere considerato un "tipo base" dal quale derivano due "specializzazioni", ReactElement e ReactText, che si differenziano per la tipologia di elemento che rappresentano all'interno della gerarchia.
ReactElement è il tipo di elemento più comune in React. Negli esempi dei precedenti capitoli, abbiamo sfruttato la sintassi JSX per invocare le funzioni del Virtual DOM di React allo scopo di creare elementi ed eseguirne il rendering all'interno della pagina.
Ciascun ReactElement è quindi una rappresentazione virtuale, dal footprint più leggero possibile, di un comune elemento presente nel DOM nativo della pagina.
ReactText è invece l'oggetto che si utilizza per la virtualizzazione dei nodi del DOM che contengono testo.
Creare elementi ReactNode
Nonostante abbiamo approfondito nel dettaglio il Virtual DOM solo ora, negli esempi delle lezioni precedenti abbiamo già inconsciamente fatto uso di alcune funzioni che consentono di creare elementi e aggiungerli alla gerarchia virtuale di React.
Nello specifico, abbiamo invocato la funzione React.createElement(), con la quale abbiamo creato istanze di oggetti corrispondenti ai singoli elementi.
Riprendiamo l'esempio "Hello World":
ReactDOM.render(
<HelloWorld />,
document.getElementById('hello')
);
Avremmo potuto scrivere lo stesso blocco di codice in questo modo:
ReactDOM.render(
React.createElement('HelloWorld'),
document.getElementById('hello')
);
In questo esempio, HelloWorld
è il nome di un nuovo elemento che abbiamo creato ex novo tramite la funzione React.createClass(), ma è possibile anche creare oggetti che rappresentano elementi HTML standard, già forniti di serie con React, come nell'esempio che segue:
ReactDOM.render(
React.createElement('hr'),
document.getElementById('container')
);
In questo caso, stiamo creando un elemento <hr>
che visualizza una linea orizzontale nella pagina. Volendo utilizzare la sintassi JSX, il codice si trasforma in questo modo:
ReactDOM.render(<hr />, document.getElementById('container'));
È bene sottolineare una volta di più che le due forme sono esattamente equivalenti in termini di risultato ottenuto. Nel blocco che fa uso della sintassi JSX tuttavia, la chiamata alla funzione React.createElement() viene semplificata rendendola "HTML-like", e vedremo nelle lezioni che seguiranno come essa rappresenti un valido aiuto rispetto all'uso diretto della funzione React.
Parametri di creazione degli elementi
La funzione React.createElement() accetta diversi parametri oltre al nome dell'elemento. Qui di seguito è riportata la "firma" della funzione come descritta nella documentazione ufficiale:
ReactElement createElement(
string/ReactClass type,
[object props],
[children ...]
)
Il primo parametro type accetta una stringa con il nome dell'elemento da creare per il rendering, oppure un riferimento all'oggetto ottenuto dalla funzione React.createClass() che invochiamo per definire un nuovo tipo di elemento.
var titleElement = React.createElement('h1');
Il secondo parametro props consente di specificare le proprietà dell'elemento: si tratta dell'oggetto che diviene accessibile nel codice del componente tramite this.props e che contiene i valori delle proprietà immutabili, a differenza dello stato che viene gestito internamente dal componente una volta inizializzato al suo interno.
var titleElement = React.createElement('h1', { style: { fontSize: 'larger'} });
Il terzo parametro children consente di specificare i "figli", ossia gli elementi che saranno contenuti all'interno dell'elemento in fase di creazione. Al parametro è possibile specificare un singolo ReactNode, ossia un elemento di tipo ReactElement o ReactText per rappresentare rispettivamente un elemento complesso oppure un semplice contenitore di testo; in alternativa, è possibile specificare un ReactFragment, quindi un array di uno o più ReactNode.
Vediamo alcuni esempi di chiamata per riassumere quanto visto sino a ora:
var h1 = React.createElement('h1', { style: { fontSize: 'larger'} }, 'Titolo');
var p1 = React.createElement('p', { className: 'text-info' }, 'Testo primo paragrafo');
var p2 = React.createElement('p', { className: 'text-info' }, 'Testo altro paragrafo');
var article = React.createElement('article', { className: 'container' }, [h1, p1, p2]);
ReactDOM.render(article, document.getElementById('container'));
È abbastanza semplice immaginare come, allo stesso modo, si potrebbe creare una lista di elementi non ordinata o altre strutture tipiche delle applicazioni Web.
Utilizzando la sintassi JSX, l'esempio precedente potrebbe essere semplificato sia dal punto di vista della lunghezza del codice sia in termini di leggibilità, poiché molto simile alla versione HTML:
var articleElement =
<article className='container'>
<h1 style={{fontSize: 'larger'}}>Titolo principale</h1>
<p className='text-info'>Testo del primo paragrafo</p>
<p className='text-info'>Testo del secondo paragrafo</p>
</article>;
ReactDOM.render(articleElement, document.getElementById('container'));
Ora che abbiamo approfondito il Virtual DOM e le API fondamentali per interagire con esso, nelle prossime lezioni entreremo nel dettaglio degli elementi che costituiscono la gerarchia virtuale costruita da React analizzando il ciclo di vita dei componenti e aggiungendovi nuove funzionalità.