Nelle precedenti lezioni della nostra Guida a React, abbiamo introdotto alcuni dei concetti chiave per lo sviluppo delle applicazioni in React. Abbiamo più volte fatto riferimento ai Componenti React (React Components) e abbiamo visto come sia teoricamente possibile scomporre un’intera applicazione in più componenti indipendenti. Esaminiamo ora in dettaglio come sia possibile creare dei componenti in React.
In React è possibile definire un Componente in diversi modi, ognuno dei quali ha dei vantaggi e svantaggi. I componenti da noi definiti dovranno avere un nome che inizia con una lettera maiuscola.
Functional Components: definire un componente tramite una funzione
Il metodo più semplice per definire un Componente è tramite una semplice funzione Javascript che riceve come unico argomento un oggetto chiamato props e restituisce un Elemento React (React Element). Vediamo subito un semplice esempio (esempio su JSBin).
const rootNode = document.querySelector('.root');
function Hello(props) {
return <h1>Ciao, {props.nome} {props.cognome}</h1>;
}
// alternativamente, volendo usare le arrow function (sintassi ES6)
// const Hello = props =>
// <h1>Ciao, {props.nome} {props.cognome}</h1>;
ReactDOM.render(<Hello nome="Mario" cognome="Bianchi" />, rootNode);
Abbiamo definito un componente Hello che restituisce un Elemento React. Abbiamo quindi invocato la funzione ReactDOM.render() a cui abbiamo passato, come primo argomento, del codice JSX che verrà a sua volta tradotto da Babel in una chiamata alla funzione React.createElement(). Abbiamo poi passato due attributi nome e cognome all’elemento <Hello />. React si occuperà di passare al componente Hello un argomento props che è un oggetto avente le stesse proprietà che sono state passate sotto forma di attributi all’elemento <Hello />. Diremo che il componente Hello riceve due props, vale a dire le prop "nome" con valore "Mario" e "cognome" con valore "Bianchi". L’oggetto props sarà così definito:
/* Oggetto props che verrà passato da React
* come argomento al componente Hello
*/
{nome: 'Mario', cognome: 'Bianchi'}
Class Components: definire un componente usando ES6
ES6 ha introdotto una nuova sintassi per creare oggetti in Javascript più simile a quella utilizzata in altri linguaggi di programmazione anche se non è cambiato il modello esistente di ereditarietà basato sul concetto di prototipo.
In React è possibile definire un componente utilizzando la sintassi di ES6 che ci permette di creare degli oggetti in maniera più semplice. (esempio su JSBin)
const rootNode = document.querySelector('.root');
class Hello extends React.Component {
render() {
return <h1>Ciao, {this.props.name} {this.props.surname}</h1>;
}
}
ReactDOM.render(<Hello name="Mario" surname="Bianchi" />, rootNode);
Un Componente definito in questo modo, deve avere almeno un metodo render() che verrà chiamato da React per aggiornare il componente stesso. Per definire un componente React, usando la sintassi di ES6, dovremmo inoltre utilizzare la keyword extends per indicare un vincolo di ereditarietà fra il componente Hello e la "classe" base React.Component. (Come detto, in ES6 è stata introdotta una nuova sintassi più semplice da usare, ma non è cambiato il modello di ereditarietà che fa uso dell’oggetto prototype)
Anche in questo caso, otterremo il seguente risultato.
I due metodi appena visti permettono di realizzare due componenti che sono leggermente differenti. Elencheremo a breve quelle che sono le differenze fra i Functional Components (primo esempio) e Class Components (esempio appena visto)
React.createClass: definire un componente usando ES5
Un ulteriore modo per definire un componente in React, non volendo adoperare la sintassi di ES6, è tramite l’uso della funzione React.createClass(). Quest’ultima riceve come argomento un oggetto in cui deve essere definita almeno la funzione render(). Vediamo come riscrivere l’esempio precedente usando React.CreateClass(). (esempio su JSBin)
var rootNode = document.querySelector('.root');
var Hello = React.createClass({
render: function() {
var testo = 'Ciao ' + this.props.nome + ' ' + this.props.cognome;
return React.createElement('h1', null, testo);
}
});
/*
* nota: stiamo passando la variabile Hello come primo argomento
* NON una stringa
*/
ReactDOM.render(
React.createElement(
Hello,
{nome: "Mario", cognome: "Bianchi"},
null
),
rootNode
);
In quest’ultimo esempio, avremmo potuto adoperare la sintassi JSX al posto delle chiamate alla funzione React.createElement(). Così facendo, sarebbe stato però necessario includere Babel all’interno del progetto. La sintassi usata ci permette di creare un componente che è concettualmente equivalente a quello in cui avevamo adoperato la sintassi ES6. I due componenti Hello, definiti usando due sintassi diverse (ES5 e ES6), presentano le stesse funzionalità. Nel resto di questa guida adopereremo la sintassi ES6 per definire i nostri componenti.
Differenza tra Functional Component e Class Component
Abbiamo appena visto tre modi diversi per definire un componente React. Gli ultimi due sono sostanzialmente equivalenti. Il primo metodo (Functional Components) genera invece un componente che ha delle caratteristiche peculiari, avendo delle funzionalità limitate. Nel caso dei Componenti (Class Component) definiti con la sintassi (class NomeComponente extends React.Component) avremmo potuto definire altri metodi oltre al metodo render() (vedremo degli esempi nei prossimi articoli). Ciò non è possibile nel caso dei Functional Component. Riassumiamo quindi quali sono le caratteristiche di un componente definito tramite una semplice funzione (Functional Component):
- Sono appunto delle normalissime funzioni.
- Sono semplici da riutilizzare e testare.
- Vengono utilizzati principalmente per i componenti che non hanno una complicata logica interna e sono creati con lo scopo di strutturare l’interfaccia grafica dell’applicazione.
- Hanno funzionalità limitate.
- Non è possibile definire uno stato interno del componente. (parleremo nei prossimi articoli dell’oggetto State che può essere usato all’interno dei Class Components)
- Non è necessario utilizzare la keyword this all’interno di questi componenti.
- Non sono presenti i cosiddetti "lifecycle hooks" (parleremo del ciclo di vita di un componente nei prossimi articoli). Ogni Class Component è invece caratterizzato da un ciclo di vita e oltre al metodo render(), è possibile definire alcuni precisi metodi che verranno invocati da React prima o dopo la funzione render(), durante la fase di inizializzazione o aggiornamento del componente.
Nei prossimi articoli approfondiremo il tema dei componenti in React essendo uno dei concetti più importanti dell’intera libreria.