Costruiremo una semplice ma realistica casella dei commenti che puoi inserire in un blog, una versione base dei commenti in tempo reale offerti da Disqus, LiveFyre o Facebook.
Forniremo:
* Una vista di tutti i commenti
* Un modulo per inviare un commento
* Hook perché tu fornisca un backend personalizzato
Avrà anche un paio di caratteristiche interessanti:
* **Commenti ottimistici:** i commenti appaiono nella lista prima che vengano salvati sul server, in modo da sembrare più veloce.
* **Aggiornamenti in tempo reale:** i commenti degli altri utenti sono aggiunti alla vista dei commenti in tempo reale.
* **Formattazione Markdown:** gli utenti possono utilizzare il Markdown per formattare il proprio testo.
### Vuoi saltare tutto questo e vedere semplicemente il sorgente?
[It's all on GitHub.](https://github.com/reactjs/react-tutorial)
### Eseguire un server
Per cominciare questo tutorial dobbiamo richiedere un server in esecuzione. Questo servirà puramente come un endpoint per le API che useremo per ottenere e salvare i dati. Per rendere questo compito il più semplice possibile, abbiamo creato un seplice server in un numero di linguaggi di scripting che fa esattamente ciò che ci serve. **Puoi [leggere il sorgente](https://github.com/reactjs/react-tutorial/) o [scaricare un file zip](https://github.com/reactjs/react-tutorial/archive/master.zip) contenente tutto ciò che ti serve per cominciare.**
Per semplicità, il server che eseguiremo usa un file `JSON` come database. Non è ciò che eseguiresti in produzione, ma rende più facile simulare ciò che faresti per consumare una API. Non appena avvii il server, supporterà il nostro endpoint API e servirà anche le pagine statiche di cui abbiamo bisogno.
### Per Cominciare
Per questo tutorial renderemo il tutto il più semplice possibile. Incluso nel pacchetto del server discusso in precedenza si trova un file HTML su cui lavoreremo. Apri `public/index.html` nel tuo editor preferito. Dovrebbe apparire simile a quanto segue (con qualche piccola differenza, aggiungeremo un tag `<script>` aggiuntivo in seguito):
// To get started with this tutorial running your own code, simply remove
// the script tag loading scripts/example.js and start writing code here.
</script>
</body>
</html>
```
Nel resto di questo tutorial, scriveremo il nostro codice JavaScript in questo tag script. Non disponiamo di alcun aggiornamento in tempo reale avanzato, quindi dovremo aggiornare il browser per vedere gli aggiornamenti dopo il salvataggio. Segui il tuo progresso aprendo `http://localhost:3000` nel tuo browser (dopo aver avviato il server). Quando carichi la pagina per la prima volta senza apportare cambiamenti, vedrai il risultato finale di ciò che ci apprestiamo a costruire. Quando sei pronto per cominciare a lavorare, elimina il tag `<script>` precedente e quindi sei pronto a continuare.
> Nota:
>
> Abbiamo incluso jQuery perché vogliamo semplificare il codice delle nostre chiamate ajax future, ma **NON** è richiesto per far funzionare React.
### Il tuo primo componente
In React ciò che importa sono i componenti modulari e componibili. Per il nostro esempio della casella dei commenti, avremo la seguente struttura dei componenti:
```
- CommentBox
- CommentList
- Comment
- CommentForm
```
Costruiamo il componente `CommentBox`, che consiste in un semplice `<div>`:
Nota che i nomi degli elementi nativi HTML cominciano con una lettera minuscola, mentre i nomi di classe personalizzati di React cominciano con una lettera maiuscola.
#### Sintassi JSX
La prima cosa che noterai è la sintassi simile a XML nel tuo JavaScript. Abbiamo un semplice preprocessore che traduce lo zucchero sintattico a questo semplice JavaScript:
```javascript
// tutorial1-raw.js
var CommentBox = React.createClass({displayName: 'CommentBox',
Il suo uso è opzionale ma abbiamo trovato la sintassi JSX più facile da usare del semplice JavaScript. Leggi maggiori dettagli sull'[articolo sulla sintassi JSX](/react/docs/jsx-in-depth.html).
#### Cosa sta succedendo?
Passiamo dei metodi in un oggetto JavaScript a `React.createClass()` per creare un nuovo componente React. Il più importante di questi metodi è chiamato `render` il quale restituisce un albero di componenti React che saranno eventualmente visualizzati come HTML.
I tag `<div>` non sono veri nodi DOM; sono istanze dei componenti React `div`. Puoi pensare a questi come marcatori o a elementi di dati che React sa come gestire. React è **sicuro**. Non stiamo generando stringhe HTML quindi la protezione XSS è predefinita.
Non devi necessariamente restituire semplice HTML. Puoi anche restituire un albero di componenti costruiti da te (o da qualcun altro). Questo è ciò che rende React **componibile**: una caratteristica chiave dei front-end manutenibili.
Costruiamo degli scheletri per `CommentList` e `CommentForm` che saranno, nuovamente, dei semplici `<div>`. Aggiungi questi due componenti al tuo file, mantenendo la dichiarazione esistente di `CommentBox` e la chiamata a `ReactDOM.render`:
Successivamente, aggiorna il componente `CommentBox` per utilizzare questi due nuovi componenti:
```javascript{6-8}
// tutorial3.js
var CommentBox = React.createClass({
render: function() {
return (
<divclassName="commentBox">
<h1>Commenti</h1>
<CommentList/>
<CommentForm/>
</div>
);
}
});
```
Nota come stiamo mescolando tag HTML e i componenti che abbiamo costruito. I componenti HTML sono componenti regolari React, proprio come quelli che definisci, con una differenza. Il compilatore JSX riscriverà automaticamente i tag HTML come espressioni `React.createElement(tagName)` e lascerà tutto il resto inalterato. Questo è per impedire che il namespace globale venga inquinato.
### Usare le proprietà
Creiamo il componente `Comment`, che dipenderà dai dati passatigli dal suo genitore. I dati passati da un componente genitore sono disponibili come una 'proprietà' nel componente figlio. Queste 'proprietà' sono accessibili attraverso `this.props`. Usando le proprietà, saremo in grado di leggere i dati passati al componente `Comment` dal componente `CommentList`, e visualizzare del markup:
```javascript
// tutorial4.js
var Comment = React.createClass({
render: function() {
return (
<divclassName="comment">
<h2className="commentAuthor">
{this.props.author}
</h2>
{this.props.children}
</div>
);
}
});
```
Racchiudendo un'espressione JavaScript dentro parentesi graffe all'interno di JSX (sia come attributo che come figlio), puoi inserire del testo o componenti React all'interno dell'albero. Accediamo per nome ad attributi passati al componente tramite chiavi in `this.props` e ciascun elemento annidato come `this.props.children`.
### Proprietà dei Componenti
Adesso che abbiamo definito il componente `Comment`, vogliamo passargli il nome dell'autore e il testo del commento. Questo ci permette di riutilizzare lo stesso codice per ciascun commento individuale. Ora aggiungiamo dei commenti all'interno del nostro `CommentList`:
```javascript{6-7}
// tutorial5.js
var CommentList = React.createClass({
render: function() {
return (
<divclassName="commentList">
<Commentauthor="Pete Hunt">Questo è un commento</Comment>
<Commentauthor="Jordan Walke">Questo è un *altro* commento</Comment>
</div>
);
}
});
```
Nota che abbiamo passato dei dati dal componente genitore `CommentList` al componente figlio `Comment`. Ad esempio, abbiamo passato *Pete Hunt* (tramite un attributo) e *Questo è un commento* (tramite un nodo figlio simil-XML) al primo `Comment`. Come detto in precedenza, il componente `Comment` accederà a queste 'proprietà' attraverso `this.props.author` e `this.props.children`.
### Aggiungiamo il Markdown
Il Markdown è una maniera semplice di formattare il tuo testo in linea. Ad esempio, racchiudendo il testo con asterischi gli aggiungerà dell'enfasi.
Per prima cosa, aggiungiamo la libreria di terze parti **marked** alla tua applicazione. Questa è una libreria JavaScript che prende il testo Markdown e lo converte in HTML nativo. Per fare ciò è richiesto un tag script nel tag head (che abbiamo già incluso nel playground React):
Successivamente, convertiamo il testo del commento da Markdown e scriviamolo:
```javascript{9}
// tutorial6.js
var Comment = React.createClass({
render: function() {
return (
<divclassName="comment">
<h2className="commentAuthor">
{this.props.author}
</h2>
{marked(this.props.children.toString())}
</div>
);
}
});
```
Tutto ciò che stiamo facendo qui è chiamare la libreria marked. Dobbiamo convertire `this.props.children` dal testo racchiuso di React a una stringa che marked è in grado di capire, quindi vi chiamiamo esplicitamente `toString()`.
Ma c'è un problema! I nostri commenti visualizzati appaiono come segue nel browser: "`<p>`Questo è un `<em>`altro`</em>` commento`</p>`". Noi vogliamo che questi tag vengano in realtà visualizzati come HTML.
Questo è il risultato della protezione di React da parte di un [attacco XSS](https://en.wikipedia.org/wiki/Cross-site_scripting). C'è una maniera di aggirare questo comportamento, ma il framework ti avvisa di non farlo:
```javascript{4,10}
// tutorial7.js
var Comment = React.createClass({
rawMarkup: function() {
var rawMarkup = marked(this.props.children.toString(), {sanitize: true});
return { __html: rawMarkup };
},
render: function() {
return (
<divclassName="comment">
<h2className="commentAuthor">
{this.props.author}
</h2>
<spandangerouslySetInnerHTML={this.rawMarkup()}/>
</div>
);
}
});
```
Questa è una speciale API che rende intenzionalmente difficile inserire HTML nativo, ma per marked ci avvantaggeremo di questa possibilità.
**Ricorda:** usando questa funzionalità stai assumendo che marked sia sicuro. In questo caso, passiamo `sanitize: true` che istruisce marked a fare l'escape di ogni markup HTML nel sorgente, anziché restituirlo inalterato.
### Collega il modello dei dati
Finora abbiamo inserito i commenti direttamente nel codice sorgente. Invece, visualizziamo un pacchetto di dati JSON nella lista dei commenti. In seguito questi verranno restituiti dal server, ma per adesso scriviamoli nel tuo sorgente:
```javascript
// tutorial8.js
var data = [
{author: "Pete Hunt", text: "Questo è un commento"},
{author: "Jordan Walke", text: "Questo è un *altro* commento"}
Dobbiamo inserire questi dati in `CommentList` in maniera modulare. Modifica `CommentBox` e la chiamata a `ReactDOM.render()` per passare questi dati a `CommentList` tramite proprietà:
Adesso che i dati sono disponibili in `CommentList`, visualizziamo i commenti dinamicamente:
```javascript{4-10,13}
// tutorial10.js
var CommentList = React.createClass({
render: function() {
var commentNodes = this.props.data.map(function (comment) {
return (
<Commentauthor={comment.author}>
{comment.text}
</Comment>
);
});
return (
<divclassName="commentList">
{commentNodes}
</div>
);
}
});
```
Tutto qui!
### Richiedere dati dal server
Sostituiamo i dati scritti nel codice con dati dinamici ottenuti dal server. Rimuoveremo le proprietà dei dati e le sostituiremo con uno URL da richiedere:
Questo componente differisce dal precedente perché dovrà effettuare un nuovo rendering di se stesso. Il componente non avrà dati finché la risposta del server non sia disponibile, e a quel punto il componente potrebbe dover visualizzare dei nuovi commenti.
Nota: il codice non funzionerà a questo passo.
### Stato reattivo
Finora, basandosi sulle sue proprietà, ogni componente si è visualizzato solo una volta. I valori di `props` sono immutabili: sono passati dal genitore e sono "posseduti" dal genitore. Per implementare le interazioni, introduciamo uno **stato** mutevole nel componente. `this.state` è privato al componente e può essere cambiato chiamando `this.setState()`. Quando lo stato si aggiorna, il componente effettua nuovamente il rendering di se stesso.
I metodi `render()` sono scritti dichiarativamente come funzioni di `this.props` e `this.state`. Il framework garantisce che la UI sia sempre consistente con gli input.
Quando il server ci fornisce i dati, dovremo cambiare i dati dei commenti in nostro possesso. Aggiungiamo un array di dati dei commenti al componente `CommentBox` come il suo stato:
```javascript{3-5,10}
// tutorial12.js
var CommentBox = React.createClass({
getInitialState: function() {
return {data: []};
},
render: function() {
return (
<divclassName="commentBox">
<h1>Commenti</h1>
<CommentListdata={this.state.data}/>
<CommentForm/>
</div>
);
}
});
```
`getInitialState()` viene eseguito esattamente una volta durante il ciclo di vita del componente e imposta lo stato iniziale del componente stesso.
#### Aggiornare lo stato
Quando il componente è creato per la prima volta, vogliamo richiedere tramite GET del JSON dal server e aggiornare lo stato per riflettere i dati più recenti. Useremo jQuery per effettuare una richiesta asincrona al server che abbiamo avviato in precedenza per richiedere i dati che ci servono. Somiglieranno a qualcosa di simile:
```json
[
{"author": "Pete Hunt", "text": "Questo è un commento"},
{"author": "Jordan Walke", "text": "Questo è un *altro* commento"}
Qui, `componentDidMount` è un metodo chiamato automaticamente da React quando un componente viene visualizzato. La chiave agli aggiornamenti dinamici è la chiamata a `this.setState()`. Sostituiamo il vecchio array di commenti con il nuovo ottenuto dal server e la UI si aggiorna automaticamente. Per via di questa reattività, è richiesto soltanto un piccolo cambiamento per aggiungere gli aggiornamenti in tempo reale. Qui useremo un semplice polling, ma potrai facilmente usare WebSockets o altre tecnologie.
Tutto ciò che abbiamo fatto finora è spostare la chiamata AJAX in un metodo a parte e chiamarlo quando il componente viene caricato per la prima volta e successivamente ogni 2 secondi. Prova ad eseguire questa versione nel tuo browser e a cambiare il file `comments.json` (si trova nella stessa directory del tuo server); entro 2 secondi i cambiamenti saranno visibili!
### Aggiungere nuovi commenti
È giunto il momento di costruire il modulo. Il nostro componente `CommentForm` deve chiedere all'utente il nome e un testo del commento, e inviare una richiesta al server per salvare il commento.
```javascript{5-9}
// tutorial15.js
var CommentForm = React.createClass({
render: function() {
return (
<formclassName="commentForm">
<inputtype="text"placeholder="Il tuo nome"/>
<inputtype="text"placeholder="Di' qualcosa..."/>
<inputtype="submit"value="Invia"/>
</form>
);
}
});
```
Rendiamo il modulo interattivo. Quando l'utente invia il modulo, dobbiamo ripulirlo, inviare una richiesta al server, e aggiornare la lista dei commenti. Per cominciare, ascoltiamo l'evento `submit` del modulo e ripuliamolo.
React assegna i gestori degli eventi ai componenti usando una convenzione di nomi camelCased. Assegnamo un gestore `onSubmit` al modulo in maniera che ripulisca i campi del modulo quando il modulo stesso è inviato con un input valido.
Chiamiamo `preventDefault()` sull'evento per prevenire l'azione predefinita del browser per l'invio del modulo.
Usiamo l'attributo `ref` per assegnare un nome a un componente figlio e `this.refs` per riferirsi al componente. Possiamo chiamare `ReactDOM.findDOMNode(component)` su di un componente per ottenere l'elemento nativo del DOM del browser.
Quando un utente invia un commento, dobbiamo aggiornare la lista dei commenti per includere il nuovo commento. Ha senso posizionare questa logica in `CommentBox` dal momento che `CommentBox` possiede lo stato che rappresenta la lista dei commenti.
Dobbiamo passare i dati dal componente figlio su fino al suo genitore. Lo facciamo nel metodo `render` del nostro genitore passando una nuova callback (`handleCommentSubmit`) al figlio, legandola all'evento `onCommentSubmit` del figlio. Quando questo evento viene emesso, la callback verrà eseguita:
La nostra applicazione è adesso completa, ma aspettare che la richiesta completi prima di vedere il commento apparire nella lista la fa sembrare lenta. Possiamo aggiungere ottimisticamente questo commento alla lista per fare apparire l'applicazione più veloce.
Hai appena costruito una casella di commenti in pochi semplici passi. Leggi maggiori dettagli sul [perché usare React](/react/docs/why-react.html), o approfondisci [la guida di riferimento dell'API](/react/docs/top-level-api.html) e comincia ad hackerare! In bocca al lupo!