--- id: tutorial title: "Tutorial: Introduzione a React" layout: tutorial sectionid: tutorial permalink: tutorial/tutorial.html redirect_from: - "docs/tutorial.html" - "docs/why-react.html" - "docs/tutorial-ja-JP.html" - "docs/tutorial-ko-KR.html" - "docs/tutorial-zh-CN.html" --- Questo tutorial non presuppone alcuna pre-esistente conoscenza di React. ## Prima di Cominciare il Tutorial {#before-we-start-the-tutorial} Costruiremo un piccolo gioco durante questo tutorial. **Potresti essere tentato di risparmiartelo perché non sviluppi giochi solitamente -- ma dagli una possibilità, non te ne pentirai.** Le tecniche che imparirai nel tutorial sono fondamentali allo sviluppo di ogni tipo di applicazione, acquisirle ti darà una profonda conoscenza di React. >Suggerimento > >Questo tutorial è stato creato per persone che preferiscono **imparare mettendo in pratica**. Se preferisci imparare i concetti a partire dalle basi, dai uno sguardo alla nostra [guida passo passo](/docs/hello-world.html). Potresti trovare questo tutorial e la guida complementari l'uno con l'altra. Il tutorial è diviso nelle seguenti sezioni: * [Setup per il Tutorial](#setup-for-the-tutorial) ti darà **un punto di partenza** per seguire il tutorial. * [Panoramica](#overview) ti spiegherà **i fondamentali** di React: componenti, props e state. * [Finire il Gioco](#completing-the-game) ti spiegherà **le tecniche più comuni** nello sviluppo con React. * [Aggiungere "Viaggio Nel Tempo"](#adding-time-travel) ti darà **una profonda conoscenza** delle uniche potenzialità di React. Non devi completare tutte le sezioni in una volta per guadagnare qualcosa da questo tutorial. Prova a seguirlo fin quando puoi -- anche se è solo per una o due sezioni. Va bene lo stesso se preferisci copiare ed incollare il codice lungo il tutorial, tuttavia, ti raccomandiamo di scriverlo a mano. Ti aiuterà a sviluppare memoria muscolare ed a capire meglio i concetti espressi. ### Cosa Stiamo Costruendo? {#what-are-we-building} In questo tutorial, ti mostreremo come costruire in React una versione interattiva del gioco tic-tac-toe (conosciuto anche come "tris"). Qui puoi vedere cosa costruiremo: **[Risultato Finale](https://codepen.io/gaearon/pen/gWWZgR?editors=0010)**. Se non capisci il codice, o se non riconosci la sintassi, non ti preoccupare! L'obiettivo di questo tutorial è appunto di aiutarti a capire React e la sua sintassi. Ti consigliamo di guardare il gioco prima di continuare. Una delle funzionalità che noterai è che c'è una lista numerata a destra del piano di gioco. Questa lista contiene l'elenco delle mosse che sono avvenute durante una partita e si aggiorna man mano che il gioco prosegue. Puoi chiudere il gioco non appena ci hai familiarizzato. Cominceremo con un template più semplice in questo tutorial. Nel passo successivo ti aiuteremo ad impostare i prerequisiti, cosicchè potrai costruire il gioco tu stesso/a. ### Prerequisiti {#prerequisites} Presupponiamo che tua abbia familiarità con HTML e JavaScript, ma dovresti comunque essere in grado di seguire anche se provieni da un diverso linguaggio di programmazione. Inoltre, daremo per scontato che tu abbia familiarità con concetti di programmazione come funzioni, oggetti, arrays e classi, anche se queste ultime hanno minore importanza in questo contesto. Se vuoi rinfrescare o dare un primo sguardo alle basi in JavaScript, ti raccomandiamo la lettura di [questa guida](https://developer.mozilla.org/it/docs/Web/JavaScript/Una_reintroduzione_al_JavaScript). Tieni presente che usiamo anche alcune funzionalità di ES6 -- una recente versione di JavaScript. In questo tutorial, useremo [arrow functions / funzioni a freccia](https://developer.mozilla.org/it/docs/Web/JavaScript/Reference/Functions_and_function_scope/Arrow_functions), [classi](https://developer.mozilla.org/it/docs/Web/JavaScript/Reference/Classes), [`let`](https://developer.mozilla.org/it/docs/Web/JavaScript/Reference/Statements/let), e [`const`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const). Puoi usare [Babel REPL](babel://es5-syntax-example) per vedere il codice compilato a partire da ES6. ## Setup per il Tutorial {#setup-for-the-tutorial} Ci sono due modi per completare questo tutorial: puoi scrivere codice nel tuo browser, o puoi configurare un ambiente di sviluppo locale sul tuo computer. ### Opzione 1: Scrivi Codice nel Browser {#setup-option-1-write-code-in-the-browser} Questo è il metodo più veloce! Prima di tutto, apri questo **[Codice Iniziale](https://codepen.io/gaearon/pen/oWWQNa?editors=0010)** in un nuovo tab. Il nuovo tab dovrebbe mostrare una nuova partita di tic-tac-toe ed il relativo codice React. In questo tutorial modificheremo quel codice. Se hai scelto questa opzione, puoi saltare la seconda opzione ed il relativo setup ed andare direttamente alla sezione [Panoramica](#overview) per una panoramica su React. ### Opzione 2: Setup Ambiente di Sviluppo Locale {#setup-option-2-local-development-environment} Il contenuto di questa sezione è completamente opzionale e non necessario al completamento di questo tutorial!
Opzionale: Istruzioni per proseguire nel tuo ambiente locale usando il tuo editor di testo preferito Questo setup richiede qualche piccolo sforzo aggiuntivo ma ti permette di completare il tutorial usando un editor a tua scelta. Ecco i passi da seguire: 1. Accertati di avere una versione recente di [Node.js](https://nodejs.org/en/) installata. 2. Segui le [istruzioni di installazione di Create React App](/docs/create-a-new-react-app.html#create-react-app) per creare un nuovo progetto. ```bash npx create-react-app my-app ``` 3. Elimina tutti i files nella cartella `src/` del nuovo progetto > Nota Bene: > >**Non eliminare l'intera cartella `src`, rimuovi solo i files al suo interno.** We'll replace the default source files with examples for this project in the next step. ```bash cd my-app cd src # Se stai usando Mac o Linux: rm -f * # Oppure, se sei su Windows: del * # Infine, torna indietro alla cartella del progetto cd .. ``` 1. Aggiungi un file chiamato `index.css` nella cartella `src/` con questo [codice CSS](https://codepen.io/gaearon/pen/oWWQNa?editors=0100). 2. Aggiungi un file chiamato `index.js` nella cartella `src/` con questo [codice JS](https://codepen.io/gaearon/pen/oWWQNa?editors=0010). 3. Aggiungi queste tre linee all'inizio del file `index.js` nella cartella `src/`: ```js import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; ``` Adesso se esegui `npm start` nella cartella del progetto ed apri `http://localhost:3000` nel tuo browser, dovresti vedere una nuova partita di tic-tac-toe. Ti raccomandiamo di seguire [queste istruzioni](https://babeljs.io/docs/editors/) per configurare l'evidenziazione della sintassi nel tuo editor.
### Aiuto, Non Funziona! {#help-im-stuck} Se sei bloccato/a, dai uno sguardo alle [risorse di supporto della comunità](/community/support.html). In particolare, [Reactiflux Chat](https://discord.gg/0ZcbPKXt5bZjGY5n) è un ottimo modo per ricevere aiuto velocemente. Se non ricevi una risposta, o se non riesci a proseguire, cortesemente apri una issue e ti aiuteremo da lì. ## Panoramica {#overview} Adesso che è tutto pronto, proseguiamo con una panoramica di React! ### Cosa è React? {#what-is-react} React è una libreria JavaScript per costruire interfacce utente caratterizzata dal fatto che è dichiarativa, efficiente e flessibile. Ti permette di comporre UI complesse a partire da piccoli ed isolati stralci di codice chiamati "componenti". React ha diversi tipi di componenti, cominciamo con le sottoclassi di `React.Component`: ```javascript class ShoppingList extends React.Component { render() { return (

Lista della spesa per {this.props.name}

); } } // Esempio d'utilizzo: ``` Arriveremo a quei simpatici tags simili ad XML in un attimo. Usiamo i componenti per dire a React cosa vogliamo vedere sullo schermo. Quando i dati cambiano, React aggiorna e ridisegna i nostri componenti in modo efficiente. In questo caso, ShoppingList (lista della spesa) è una **classe componente React**, o **tipo componente React**. I componenti ricevono parametri, chiamati `props` (da "properties" ovvero proprietà), e ritornano una gerarchia di viste da visualizzare attraverso il metodo `render`. Il metodo `render` ritorna una *descrizione* di cosa vogliamo vedere sullo schermo. React prende questa descrizione e ne visualizza il risultato. In particolare, `render` ritorna un **elemento React**, che è una descrizione leggera di cosa bisogna visualizzare. La maggioranza degli sviluppatori React usa una speciale sintassi chamata "JSX" che rende queste strutture più facili da scrivere. La sintassi `
` viene trasformata a build time in `React.createElement('div')`. L'esempio di prima è equivalente a: ```javascript return React.createElement('div', {className: 'shopping-list'}, React.createElement('h1', /* ... h1 children ... */), React.createElement('ul', /* ... ul children ... */) ); ``` [Guarda la versione estesa.](babel://tutorial-expanded-version) Se vuoi curiosare, `createElement()` viene descritto con maggior dettaglio nella [API di riferimento](/docs/react-api.html#createelement), ma non lo useremo in questo tutorial. Invece, continueremo ad usare JSX. JSX ha in se tutte le funzionalità di JavaScript. Puoi inserire *qualunque* espressione JavaScript all'interno di parentesi in JSX. Ogni elemento React è un oggetto JavaScript che puoi salvare in una variabile e/o passare di quà e di là nel tuo programma. Il componente `ShoppingList` di prima visualizza solo componenti DOM predefiniti, come `
` e `
  • `. Ma puoi comporre e visualizzare anche componenti React personalizzati al suo interno. Per esempio, adesso possiamo riferifci all'intera lista della spesa scrivendo ``. Ogni componente React è incapsulato e può operare indipendentemente; ciò ci permette di costruire UI complesse a partire da semplici componenti. ## Uno Sguardo al Codice Iniziale {#inspecting-the-starter-code} Se hai scelto di lavorare sul tutorial **nel tuo browser,** apri questo codice in un nuovo tab: **[Codice Iniziale](https://codepen.io/gaearon/pen/oWWQNa?editors=0010)**. Se invece vuoi lavorare **localmente,** apri `src/index.js` nella cartella del progetto (hai già aperto questo file durante il [setup](#setup-option-2-local-development-environment)). Il Codice Iniziale è la base di quello che vogliamo costruire. Abbiamo già fornito gli stili CSS cosicchè ti potrai concentrare solo sull'imparare React e programmare il gioco tic-tac-toe. Ispezionando il codice, noterai che ci sono tre componenti React: * Square * Board * Game Il componente Square (quadrato) visualizza un singolo ` ); } } ``` Prima: ![React Devtools](../images/tutorial/tictac-empty.png) Dopo: Dovresti vedere un numero all'interno di ogni quadrato nell'output. ![React Devtools](../images/tutorial/tictac-numbers.png) **[Visualizza tutto il codice scritto finora](https://codepen.io/gaearon/pen/aWWQOG?editors=0010)** Congratulazioni! Hai appena "passato una prop" da un componente genitore Board al suo componente figlio Square. Nelle applicazioni React, è così che le informazioni circolano, dai genitori ai figli. ### Creare un Componente Interattivo {#making-an-interactive-component} Andiamo a riempire il componente Square con una "X" quando lo clicchiamo. Prima di tutto, modifichiamo il tag `button` che è ritornato dalla funzione `render()` del componente Square: ```javascript{4} class Square extends React.Component { render() { return ( ); } } ``` Adesso, se clicchiamo su uno Square, riceviamo un alert nel browser. >Nota Bene > >Al fine di risparmiarci qualche carattere e per evitare i problemi legati allo [strano comportamento di `this`](https://yehudakatz.com/2011/08/11/understanding-javascript-function-invocation-and-this/), useremo la sintassi [arrow function / funzione a freccia](https://developer.mozilla.org/it/docs/Web/JavaScript/Reference/Functions_and_function_scope/Arrow_functions) per event handlers (funzioni richiamate quando il relativo evento accade) qui e poi di seguito: > >```javascript{4} >class Square extends React.Component { > render() { > return ( > > ); > } >} >``` > >Nota come con `onClick={() => alert('click')}`, stiamo passando *una funzione* come prop `onClick`. Essa viene eseguita a seguito di un click. Dimenticare `() =>` e scrivere `onClick={alert('click')}` è un errore comune, e risulterebbe nel lanciare l'alert ogni volta che il componente viene ridisegnato (chiamata a `render()`). Come passo successivo, vogliamo far si che il componente Square si "ricordi" di essere stato cliccato, e che visualizzi il segno "X" al suo interno. Per "ricordare" cose, i componenti usano **state** (inteso come ["stato"](https://en.wikipedia.org/wiki/State_(computer_science))). I componenti React possono avere uno stato impostando `this.state` nei loro costruttori. `this.state` dovrebbe essere considerato privato (in termini di accesso) al componente React nel quale è definito. Andiamo a salvare il valore attuale di Square in `this.state`, e cambiamolo quando Square viene cliccato. Per cominciare, aggiungiamo il costruttore alla classe per inizializzarne lo stato: ```javascript{2-7} class Square extends React.Component { constructor(props) { super(props); this.state = { value: null, }; } render() { return ( ); } } ``` >Nota Bene > >Nelle [classi JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes), devi sempre chiamare `super` quando definisci il costruttore di una sottoclasse (classe derivata). Tutte le classi componente React che hanno un `constructor` devono sempre richiamare `super(props)` come prima istruzione nel costruttore. Procediamo alla modifica del metodo `render` di Square per visualizzare il valore corrente dello stato quando lo clicchiamo: * Sostituisci `this.props.value` con `this.state.value` all'interno del tag ` ); } } ``` Richiamando `this.setState` dall'handler `onClick` nel metodo `render` di Square, fondamentalmente stiamo dicendo a React di ridisegnare quello Square ogni qual volta il suo ` ); } } ``` Quando uno Square viene cliccato, viene richiamata la funzione `onClick` provvista da Board. Ecco in dettaglio come ciò avviene: 1. La prop `onClick` nel componente ` ); } ``` Abbiamo cambiato `this.props` in `props` in entrambi i casi. **[Visualizza tutto il codice scritto finora](https://codepen.io/gaearon/pen/QvvJOv?editors=0010)** >Nota Bene > >Quando abbiamo convertito Square in un componente funzione, abbiamo anche cambiato `onClick={() => this.props.onClick()}` nella versione più corta `onClick={props.onClick}` (nota l'assenza delle parentesi da *entrambi* i lati). Nella classe, avevamo usato una arrow function per avere accesso al corretto valore di `this`, nel componente funzione, al contrario, non dobbiamo preoccuparci di `this`. ### Turni {#taking-turns} Procediamo a sistemare un grosso difetto del nostro gioco: le "O" non possono essere piazzate sulla tavola. Impostiamo il fatto che la "X" sia il segno predefinito per il primo turno. Per far ciò, modifichiamo lo stato iniziale di Board nel rispettivo costruttore: ```javascript{6} class Board extends React.Component { constructor(props) { super(props); this.state = { squares: Array(9).fill(null), xIsNext: true, }; } ``` Ogni volta che un giocatore muove, `xIsNext` (booleano) viene invertito per determinare quale giocatore sarà il prossimo a muovere e lo stato viene poi salvato. Modifichiamo quindi la funzione `handleClick` di Board per invertire il valore di `xIsNext`: ```javascript{3,6} handleClick(i) { const squares = this.state.squares.slice(); squares[i] = this.state.xIsNext ? 'X' : 'O'; this.setState({ squares: squares, xIsNext: !this.state.xIsNext, }); } ``` Con questo cambiamento, "X" e "O" adesso vengono usati alternativamente di turno in turno. Dobbiamo anche cambiare il testo "status" nel `render` di Board cosicchè verremo informati a video del giocatore che deve muovere nel turno successivo: ```javascript{2} render() { const status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O'); return ( // il resto non cambia ``` Al seguito di queste modifiche, ecco il nostro componente Board: ```javascript{6,11-16,29} class Board extends React.Component { constructor(props) { super(props); this.state = { squares: Array(9).fill(null), xIsNext: true, }; } handleClick(i) { const squares = this.state.squares.slice(); squares[i] = this.state.xIsNext ? 'X' : 'O'; this.setState({ squares: squares, xIsNext: !this.state.xIsNext, }); } renderSquare(i) { return ( this.handleClick(i)} /> ); } render() { const status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O'); return (
    {status}
    {this.renderSquare(0)} {this.renderSquare(1)} {this.renderSquare(2)}
    {this.renderSquare(3)} {this.renderSquare(4)} {this.renderSquare(5)}
    {this.renderSquare(6)} {this.renderSquare(7)} {this.renderSquare(8)}
    ); } } ``` **[Visualizza tutto il codice scritto finora](https://codepen.io/gaearon/pen/KmmrBy?editors=0010)** ### Dichiarare un Vincitore {#declaring-a-winner} Adesso che possiamo visualizzare quale giocatore deve muovere nel prossimo turno, possiamo anche visualizzare quando una partita è finita ed il relativo vincitore. Per determinare il vincitore, aggiungiamo una funzione aiutante (funzioni che contribuiscono alla risoluzione dell'algoritmo, normalmente chiamate "helper functions") alla fine del file: ```javascript function calculateWinner(squares) { const lines = [ [0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6], ]; for (let i = 0; i < lines.length; i++) { const [a, b, c] = lines[i]; if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) { return squares[a]; } } return null; } ``` Richiameremo `calculateWinner(squares)` nella funzione `render` di Board per verificare se un giocatore ha vinto. In caso positivo, visualizzeremo il testo "Winner: X" oppure "Winner: O". Sostituiremo la dichiarazione di `status` nella funzione `render` di Board in questo modo: ```javascript{2-8} render() { const winner = calculateWinner(this.state.squares); let status; if (winner) { status = 'Winner: ' + winner; } else { status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O'); } return ( // il resto non cambia ``` Dobbiamo modificare anche la funzione `handleClick` di Board per far si che ritorni immediatamente, ignorando i click, nel caso in cui qualcuno ha già vinto la partita o nel caso in cui Square sia già riempito: ```javascript{3-5} handleClick(i) { const squares = this.state.squares.slice(); if (calculateWinner(squares) || squares[i]) { return; } squares[i] = this.state.xIsNext ? 'X' : 'O'; this.setState({ squares: squares, xIsNext: !this.state.xIsNext, }); } ``` **[Visualizza tutto il codice scritto finora](https://codepen.io/gaearon/pen/LyyXgK?editors=0010)** Congratulazioni! Hai una versione funzionante di tic-tac-toe! Inoltre, hai anche già imparato le basi di React. A pensarci bene, probabilmente a vincere davvero alla fine *sei tu!*. ## Aggiungere "Viaggio Nel Tempo" {#adding-time-travel} Come esercizio finale, facciamo in modo che sia possibile "andare indietro nel tempo" a mosse precedenti nel gioco. ### Salvare lo Storico delle Mosse {#storing-a-history-of-moves} Se avessimo mutato l'array `squares`, implementare il viaggio nel tempo sarebbe molto difficile. Fortunatamente, abbiamo usato `slice()` per creare una nuova copia dell'array `squares` dopo ogni mossa, [trattandolo come struttura dati immutabile](#why-immutability-is-important). Ciò ci permette di salvare ogni precedente versione dell'array `squares` e di scorrere tra i turni avvenuti. Salveremo gli array `squares` precedenti in un altro array chiamato `history` (da "storia" per rappresentare appunto lo storico delle mosse). L'array `history` rappresenta tutti gli stati della tavola, dalla prima all'ultima mossa, ed ha questa forma: ```javascript history = [ // Prima di ogni mossa { squares: [ null, null, null, null, null, null, null, null, null, ] }, // Dopo la prima mossa { squares: [ null, null, null, null, 'X', null, null, null, null, ] }, // Dopo la seconda mossa { squares: [ null, null, null, null, 'X', null, null, null, 'O', ] }, // ... ] ``` Adesso dobbiamo decidere quale componente dovrebbe possedere lo stato in `history`. ### Elevare lo Stato, Di Nuovo {#lifting-state-up-again} Anche in questo caso, vogliamo che sia il componente di più alto livello Game a visualizzare la lista delle mosse precedenti. Per questo, e dato che bisogna avere accesso ad `history` per fare ciò, salveremo lo stato `history` nel componente Game. Posizionare lo stato `history` nel componente Game ci permette di rimuovere lo stato `squares` dal suo componente figlio Board. Così come abbiamo fatto quando abbiamo ["elevato lo stato"](#lifting-state-up) dal componente Square nel componente Board, adesso dobbiamo elevarlo dal componente Board al componente di più alto livello Game. Ciò darà al componente Game pieno controllo sui dati di Board, permettendoci di istruire Board a visualizzare i turni precedenti partendo da `history`. Prima di tutto, dobbiamo impostare lo stato iniziale del componente Game nel suo costruttore: ```javascript{2-10} class Game extends React.Component { constructor(props) { super(props); this.state = { history: [{ squares: Array(9).fill(null), }], xIsNext: true, }; } render() { return (
    {/* status */}
      {/* TODO */}
    ); } } ``` Poi, dobbiamo far si che il componente Board riceva le props `squares` ed `onClick` dal componente Game. Dato che adesso abbiamo un solo handler per il click in Board per i vari Squares, dobbiamo passare la posizione di ogni Square nell'handler `onClick` per indicare quale Square è stato cliccato. Questi sono i passi necessari per trasformare il componente Board: * Rimuovere il `constructor` in Board. * Sostituire `this.state.squares[i]` con `this.props.squares[i]` nel metodo `renderSquare` di Board. * Sostituire `this.handleClick(i)` con `this.props.onClick(i)` nel metodo `renderSquare` di Board. Il componente Board adesso risulterà: ```javascript{17,18} class Board extends React.Component { handleClick(i) { const squares = this.state.squares.slice(); if (calculateWinner(squares) || squares[i]) { return; } squares[i] = this.state.xIsNext ? 'X' : 'O'; this.setState({ squares: squares, xIsNext: !this.state.xIsNext, }); } renderSquare(i) { return ( this.props.onClick(i)} /> ); } render() { const winner = calculateWinner(this.state.squares); let status; if (winner) { status = 'Winner: ' + winner; } else { status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O'); } return (
    {status}
    {this.renderSquare(0)} {this.renderSquare(1)} {this.renderSquare(2)}
    {this.renderSquare(3)} {this.renderSquare(4)} {this.renderSquare(5)}
    {this.renderSquare(6)} {this.renderSquare(7)} {this.renderSquare(8)}
    ); } } ``` Modifichiamo la funzione `render` del componente Board per far si che utilizzi l'elemento più recente nello storico per visualizzare lo stato della partita: ```javascript{2-11,16-19,22} render() { const history = this.state.history; const current = history[history.length - 1]; const winner = calculateWinner(current.squares); let status; if (winner) { status = 'Winner: ' + winner; } else { status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O'); } return (
    this.handleClick(i)} />
    {status}
      {/* TODO */}
    ); } ``` Dato che adesso è il componente Game a renderizzare lo stato della partita, possiamo rimuovere il relativo codice ridondante dal metodo `render` di Board. Dopo aver rifattorizzato, ecco la funzione `render` di Board: ```js{1-4} render() { return (
    {this.renderSquare(0)} {this.renderSquare(1)} {this.renderSquare(2)}
    {this.renderSquare(3)} {this.renderSquare(4)} {this.renderSquare(5)}
    {this.renderSquare(6)} {this.renderSquare(7)} {this.renderSquare(8)}
    ); } ``` Infine, dobbiamo spostare il metodo `handleClick` dal componente Board al componente Game. Dobbiamo inoltre modificarlo dato che lo stato del componente Game è strutturato diversamente. All'interno del metodo `handleClick`, dobbiamo concatenare i nuovi elementi all'interno di `history`. ```javascript{2-4,10-12} handleClick(i) { const history = this.state.history; const current = history[history.length - 1]; const squares = current.squares.slice(); if (calculateWinner(squares) || squares[i]) { return; } squares[i] = this.state.xIsNext ? 'X' : 'O'; this.setState({ history: history.concat([{ squares: squares, }]), xIsNext: !this.state.xIsNext, }); } ``` >Nota Bene > >Contrariamente al metodo `push()`, al quale potresti essere più abituato, il metodo `concat()` non muta l'array originale, per questo lo preferiamo. A questo punto, il componente Board richiede solo i metodi `renderSquare` e `render`. Lo stato della partita ed il metodo `handleClick` dovrebbero essere nel componente Game. **[Visualizza tutto il codice scritto finora](https://codepen.io/gaearon/pen/EmmOqJ?editors=0010)** ### Visualizzare le Mosse Precedenti {#showing-the-past-moves} Visto che stiamo memorizzando lo storico delle mosse di una partita di tic-tac-toe, possiamo ora mostrarne una lista all'utente. Abbiamo imparato in precedenza che gli elementi React sono oggetti JavaScript di prima classe; possiamo passarli ed assegnarli all'interno delle nostre applicazioni. Per renderizzare elementi multipli in React, possiamo usare un array di elementi React. In JavaScript, gli array hanno un [metodo `map()`](https://developer.mozilla.org/it/docs/Web/JavaScript/Reference/Global_Objects/Array/map) che viene comunemente usato per mappare dati in modo diverso, per esempio: ```js const numeri = [1, 2, 3]; const raddoppiati = numeri.map(x => x * 2); // [2, 4, 6] ``` Usando il metodo `map`, possiamo mappare il nostro storico delle mosse in elementi React che rappresentano i bottoni sullo schermo, e visualizzare una lista di bottoni per "saltare" alle mosse precedenti. Usiamo `map` su `history` nel metodo `render` di Game: ```javascript{6-15,34} render() { const history = this.state.history; const current = history[history.length - 1]; const winner = calculateWinner(current.squares); const moves = history.map((step, move) => { const desc = move ? 'Go to move #' + move : 'Go to game start'; return (
  • ); }); let status; if (winner) { status = 'Winner: ' + winner; } else { status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O'); } return (
    this.handleClick(i)} />
    {status}
      {moves}
    ); } ``` **[Visualizza tutto il codice scritto finora](https://codepen.io/gaearon/pen/EmmGEa?editors=0010)** Per ogni mossa nello storico delle mosse, creeremo una lista di elementi `
  • ` che contengono un bottone `
  • ); }); ``` **[Visualizza tutto il codice scritto finora](https://codepen.io/gaearon/pen/PmmXRE?editors=0010)** Cliccare su uno qualunque dei bottoni della lista causerà un errore dato che il metodo `jumpTo` non è stato ancora definito. Prima di implementarlo, aggiungeremo `stepNumber` allo stato del componente Game per indicare quale mossa stiamo visualizzando. Prima di tutto, aggiungiamo `stepNumber: 0` allo stato iniziale nel `constructor` di Game: ```js{8} class Game extends React.Component { constructor(props) { super(props); this.state = { history: [{ squares: Array(9).fill(null), }], stepNumber: 0, xIsNext: true, }; } ``` Poi, definitiamo il metodo `jumpTo` in Game per aggiornare quello `stepNumber`. Imposteremo anche `xIsNext` a true (vero) nel caso in cui il numero in cui stiamo impostando in `stepNumber` sia pari: ```javascript{5-10} handleClick(i) { // questo metodo non è cambiato } jumpTo(step) { this.setState({ stepNumber: step, xIsNext: (step % 2) === 0, }); } render() { // questo metodo non è cambiato } ``` È ora di apportare qualche cambiamento al metodo `handleClick` di Game che verrà richiamato quando si clicca su un quadrato. Lo stato `stepNumber` che abbiamo appena aggiunto adesso riflette la mossa visualizzata. Dopo ogni nuova mossa, dobbiamo aggiornare `stepNumber` aggiungendo `stepNumber: history.length` come parte del parametro alla chiamata `this.setState`. Ciò farà in modo di non restare bloccati nella stessa mossa ogni qual volta ne viene effettuata una nuova. Sostituiremo anche `this.state.history` con `this.state.history.slice(0, this.state.stepNumber + 1)`. Ciò farà in modo che nel caso in cui volessimo "andare indietro nel tempo" e poi fare una nuova mossa da quel punto, possiamo buttare via tutta la storia "futura" che diverrebbe incorretta visto che in un certo senso la stiamo riscrivendo. ```javascript{2,13} handleClick(i) { const history = this.state.history.slice(0, this.state.stepNumber + 1); const current = history[history.length - 1]; const squares = current.squares.slice(); if (calculateWinner(squares) || squares[i]) { return; } squares[i] = this.state.xIsNext ? 'X' : 'O'; this.setState({ history: history.concat([{ squares: squares }]), stepNumber: history.length, xIsNext: !this.state.xIsNext, }); } ``` Infine, modificheremo il metodo `render` del componente Game per far sì che smetta di visualizzare sempre l'ultima mossa ma visualizzi invece la mossa `stepNumber`: ```javascript{3} render() { const history = this.state.history; const current = history[this.state.stepNumber]; const winner = calculateWinner(current.squares); // il resto non cambia ``` Se clicchiamo su uno qualunque degli elementi dello storico, la tavola di gioco dovrebbe automaticamente aggiornarsi per visualizzare il relativo stato. **[Visualizza tutto il codice scritto finora](https://codepen.io/gaearon/pen/gWWZgR?editors=0010)** ### Riepilogo {#wrapping-up} Congratulazioni! Abbiamo creato un gioco tic-tac-toe che: * Ti permette di giocare, * Sa determinare quando un giocatore vince la partita, * Tiene traccia dello storico delle mosse man mano che la partita prosegue, * Permette al giocatore di rivedere lo storico e con esso le precedenti versioni della tavola di gioco. Ottimo lavoro! Ci auguriamo che tu ti senta di aver avuto una decente introduzione al funzionamento di React. Quì puoi vedere il risultato finale: **[Risultato Finale](https://codepen.io/gaearon/pen/gWWZgR?editors=0010)**. Se hai ancora del tempo a disposizione per mettere in pratica le tue nuove capacità in React, ecco alcune idee per miglioramenti che potresti apportare al gioco, elencati in ordine di difficoltà: 1. Visualizza la posizione per ogni mossa nel formato (colonna, riga) nello storico delle mosse. 2. Evidenzia l'elemento correntemente selezionato nella lista delle mosse. 3. Riscrivi Board in modo da usare due cicli per creare i quadrati invece di averli "scolpiti nel codice" (o [hardcoded](https://it.wikipedia.org/wiki/Codifica_fissa) in Inglese). 4. Aggiungi un bottone a due stati che ti permette di riordinare le mosse in ordine ascendente e discendente. 5. Quando qualcuno vince, evidenzia i tre quadrati che hanno causato la vittoria. 6. Quando la partita finisce in pareggio, visualizza il relativo messaggio. Attraverso questo tutorial, abbiamo toccato vari concetti chiave di React quali: elementi, componenti, props e state. Per una spiegazione più dettagliata di questi argomenti, dai uno sguardo al [resto della documentazione](/docs/hello-world.html). Per imparare come definire componenti, puoi leggere l'[API di riferimento di `React.Component`](/docs/react-component.html).