Sei sulla pagina 1di 29

REACT

INTRODUZIONE
React è una libreria JavaScript che nasce per diventare la soluzione per sviluppatori frontend e App mobile basate su
HTML5. React è una libreria dichiarativa basata su componenti.
Dichiarativa perchè React consente di sviluppare User Interface UI facilmente rendendo il codice più leggibile e facile
da debuggare, progettare interfacce per ogni stato della applicazione in modo che ad ogni cambio di stato React
aggiornerà solamente le parti della UI che dipendono da tali dati.
I componenti sono simili a tag html, possono essere creati componenti singoli o composti con una struttura albero,
per UI complesse. Le interazioni e la logica per i componenti sono implementate in JavaScript e questo ci consente
facilmente di passare ed accedere strutture dati complesse in vari punti della applicazione senza dover salvare
informazioni sul DOM.

COME AGGIUNGERE REACT AD UN SITO


Per aggiungere un componente React ad una pagina HTML esistente, non ci saranno requisiti di installazione.

Passo 1: Aggiungi un Contenitore DOM all’HTML (root)


Per prima cosa bisogna aggiungere, alla pagina HTML, un tag <div> vuoto per indicare il punto in cui visualizzare
qualcosa con React.
<div id="content"></div>
E bisogna assegnare a questo <div> un attributo id univoco. Questo consentirà di trovarlo con il codice JavaScript e di
visualizzare un componente React al suo interno.
Puoi posizionare un <div> “contenitore” ovunque all’interno del tag <body> e inserire tutti i contenitori DOM
indipendenti di cui hai bisogno in una pagina

Passo 2: Aggiungi i Tag Script


Successivamente, bisogna aggiungere tre tag <script> alla pagina HTML, subito prima del tag di chiusura </body>:

<!-- Carica React. -->


<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
<!-- Carica il nostro componente React. -->
<script src="script.js"></script>
</body>

I primi due tag caricano React. Il terzo carica il codice del componente.
Le versioni di sopra sono intese solo per ambienti di sviluppo, e non sono adatte per ambienti di produzione. Le
versioni minificate e ottimizzate di produzione di React sono:

<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>


<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>

Verificare che la CDN che stai usando abbia settato l’header HTTP Access-Control-Allow-Origin: *:

Passo 3: Crea un Componente React


Creare un file Javascript che definisce un componente React ed attraverso l’id del div lo si inserisce nell’HTML.
CREARE UN NUOVO PROGETTO REACT
Quando invece si deve incominciare un nuovo progetto React e man mano la applicazione cresce, nasce il bisogno di
uno strumento più integrato. Esistono diverse toolchains JavaScript consigliati per lo sviluppo di applicazioni più
complesse per ottenere tutti i vantaggi di React. Le toolchain in React aiutano a compiti come:
 Utilizzare librerie di terze parti importate da npm.
 Individuare subito errori comuni.
 Visualizzare in tempo reale l’effetto delle modifiche al codice JavaScript e CSS durante lo sviluppo.
 Ottimizzare l’output per la produzione.
Le toolchains non hanno bisogno di una configurazione per essere utilizzate.
React raccomanda queste soluzioni:
 Se si sta imparando React o creando una nuova applicazione single-page, utilizzare Create React App.
 Se si sta realizzando un sito renderizzato lato server con Node.js, utilizzare Next.js.
 Se si sta realizzando un sito orientato al contenuto statico, usare Gatsby.
 Se si sta realizzando una libreria di componenti o integrando una base di codice preesistente,
usare Toolchains Più Flessibili.

Create React App


Create React App è un ambiente confortevole per imparare React, ed è il modo migliore per iniziare a costruire una
nuova applicazione single-page in React.
Esso configura l’ambiente di sviluppo in modo da poter utilizzare le caratteristiche più recenti di JavaScript, fornisce
un’ottima esperienza di sviluppo e ottimizza la applicazione per la produzione.
Sono richiesti l’installazione di Node >= 8.10 and npm >= 5.6.
Per creare un progetto, eseguire:
npx create-react-app mia-app
cd mia-app
npm start

npx è un esecutore di pacchetti incluso in npm.


Create React App non gestisce la logica di backend o i database; crea solo una catena di build per il frontend, quindi
puo essere utilizzato con qualsiasi backend.
Quando si deve rilasciare in produzione, esegui il comando 
npm run build
 e verrà creata una build ottimizzata della applicazione nella cartella build.

Next.js
Next.js è un framework popolare e leggero per le applicazioni statiche e renderizzate lato server realizzate con
React. Include soluzioni per il routing e l’applicazione degli stili e richiede l’utilizzo di Node.js come ambiente server.

Gatsby
Gatsby è il miglior modo di creare siti statici con React, consente di utilizzare componenti React, ma il suo output è
costituito interamente da codice HTML e CSS pre-renderizzato, in modo da garantire tempi di caricamento rapidi.

Toolchains Più Flessibili


Le toolchains seguenti offrono più scelta e flessibilità, raccomandati per gli utenti più esperti:
 Neutrino  include un preset per le applicazioni React e per i componenti React.
 Nx  permette lo sviluppo di monorepo full-stack, con supporto integrato per React, Next.js, Express, ed altro.
 Parcel è un builder di applicazioni rapido e senza configurazioni che funziona con React.
 Razzle framework di renderizzazione lato server che non ha bisogno di configurazioni, offre più flessibilità di
Next.js.

STRUTTURA FILE PROGETTO CON CREATE-REACT-APP


Una volta creato il progetto con create-react-app, vengono creati vari file e cartelle.

Il file package.json
La cartella di progetto include un set di package già installati, facenti parte di Node.js, contenuti all’interno della
directory node_modules.
Una parte dei package sono necessari per l’esecuzione dell’applicazione e affinché essa possa funzionare.
Vi sono poi altri package, che forniscono invece strumenti di supporto per la verifica del codice, l’avvio di un server
Web per il debug, l’esecuzione di test automatizzati, l’assemblaggio dei file e delle risorse per il rilascio in produzione
e altro ancora. Essi non sono quindi indispensabili a runtime, ma solo in fase di sviluppo.
Il file package.json: si tratta di un file presente nelle applicazioni e package scritte per Node.js, contiene un
oggetto JSON che riepiloga le informazioni salienti del package, come il nome (name) e la versione (version), le
dipendenze necessarie a runtime (dependencies) e quelle per il solo sviluppo (devDependencies), più una serie di
comandi che possono essere eseguiti attraverso npm, il package manager di Node.js, definiti nella proprietà scripts.

I comandi react-scripts
create-react-app include il package react-scripts che fornisce una serie script già pronti in grado di eseguire diverse
operazioni dal Prompt dei Comandi.
Aprendo il Promt e spostandosi nella cartella del progetto, è possibile lanciare gli script con
npm Comando.
I comandi disponibili sono:
- npm start esegue la transpilazione del codice sorgente dell’applicazione, mostrando eventuali errori. Al
termine del processo, viene attivato il server Web per il debugging e aperto il browser per visualizzare la
pagina iniziale dell’applicazione all’indirizzo localhost e alla porta predefinita (3000). Se il browser non
mostra il contenuto atteso, verificare gli eventuali errori nella scheda Console.
- npm build: esegue il build del progetto creando la directory omonima e generando al suo interno i file
assemblati dell’applicazione, ottimizzati per il rilascio in ambiente di produzione. I tool di bundling accorpano
e impacchettano i file necessari al funzionamento dell’applicazione, e avviano il processo di minification per
ridurre il peso dei file che il browser dovrà scaricare, massimizzando le performance.
- npm test: prepara la suite di test per l’esecuzione. Generalmente, il tool rimane attivo e in ascolto per
eseguire nuovamente i test a fronte di modifiche ai sorgenti dell’applicazione.
- npm eject: comando irreversibile che si esegue quando si vuole rinunciare al supporto di create-react-app. Il
comando rimuove dal progetto la dipendenza dal tool ed estrae i file di configurazione per Webpack, Babel e
gli altri tool a cui si appoggia, lasciandone il controllo completo nelle mani dello sviluppatore.

File sorgenti src


La cartella src del progetto contiene i file sorgenti veri e propri, che costituiscono i “mattoni” della applicazione: essi
comprendono file JavaScript con il codice dei componenti, file CSS con i fogli di stile, eventuali “assets” (immagini,
icone, font, ecc.).
Nella cartella troviamo il file App.js, che rappresenta il componente principale dell’applicazione (root DOM) e che
ospiterà al suo interno tutti i componenti “figli” che andranno a comporre l’interfaccia utente.
Il componente che farà da contenitore si troverà nel file index.js, nella cartella public e che funge da “entry point”
della applicazione.

JSX: COMPONENTI ED ELEMENTI


JSX è una sintassi che può sembrare HTML, ma è un’estensione della sintassi JavaScript che consente di creare
elementi base che compongono i componenti. I componenti poi vengono reindirizzati nel DOM
dell’applicazione. Puoi pensare agli elementi come a descrizioni di ciò che vuoi vedere sullo schermo. React
legge questi oggetti e li utilizza per costruire il DOM e tenerlo aggiornato.
Quindi l’ intera applicazione ha una struttura ad albero DOM, è consigliato creare in file .js distinti i singoli
componenti e reindirizzarli poi al DOM (index.html) attraverso il file index.js.

In React, gli elementi di un componente devono avere un solo elemento padre, ad esempio:
<div>
<h1> Hello World</h1>
<div>
<h2> Primo esempio<h2>
In questo caso, darebbe un errore. Se vogliamo scrivere il codice precedente, ritornando più elementi,
correttamente e senza inserire il secondo elemento nell’elemento padre div, o creare un altro div, è possibile
avvolgerli in <React.Fragment>...</React.Fragment> che consente di restituire elementi multipli come
risultato di un metodo render() senza dover creare un elemento DOM aggiuntivo per contenerli.
In pratica é possibile scrivere gli elementi dei componenti direttamente in Javascript, infatti, JSX è opzionale
e non richiesto per utilizzare React, in quanto esso verrá poi convertito in Javascript, ma è molto piú
comodo, semplice e leggibile. Il tool Babel converte, infatti, il codice JSX in JavaScript, in chiamate a
React.createElement, ad esempio:

const element = <h1 className="saluto">Hello, world!</h1>;

viene convertito in:

const element = React.createElement(


'h1',
{className: 'saluto'},
'Hello, world!'
);

Codice Javascript in JSX


All’interno degli elementi JSX è possibile eseguire codice Javascript (espressioni, variabili, function, ecc) inserendolo
in parentesi graffe { }, ad esempio includiamo il risultato della chiamata ad una funzione JavaScript, in un
elemento <h1>.
const element = <h1> Hello, {formatName(user)} </h1>;

const user = {
firstName: 'Giuseppe',
lastName: 'Verdi'
};

function formatName(user) {
return user.firstName + ' ' + user.lastName;
}

ReactDOM.render(element, document.getElementById('root'));

Vediamo in questo esempio che è possibile creare elementi e assegnarli a variabili;


Nell’elemento, nelle parentesi {} viene eseguita una chiamata a una function javascript che prende i dati da un
oggetto user. E infine l’elemento viene infine reindirizzato al DOM attraverso il nome della variabile.

È possibile utilizzare JSX all’interno di istruzioni if e cicli for, assegnarlo a variabili, utilizzarlo come argomento di
una funzione e restituirlo come risultato di una funzione.
Non aggiungere le virgolette attorno alle parentesi graffe quando si include un’espressione JavaScript in un attributo.
Dovresti utilizzare o le virgolette (per le stringhe) o le parentesi graffe (per le espressioni), ma mai entrambe nello
stesso attributo.

React DOM utilizza la convenzione camelCase nell’assegnare il nome agli attributi, invece che quella utilizzata
normalmente nell’HTML, e modifica il nome di alcuni attributi, ad esempio,  l’attributo class diventa className in
JSX e tabindex diventa tabIndex.

I componenti React implementano un metodo render() che riceve dati in input e ritorna cosa deve visualizzare.

PRIMA APP REACT: Hello World


Esempio di app react che crea un componente HelloMessage tamite una classe

class HelloMessage extends React.Component {


render() {
return (
<div>
<h1>Hello {this.props.name}</h1>
</div>
);
}
}
ReactDOM.render(<HelloMessage name="World" />, document.getElementById('root'));

PROGETTO REACT OROLOGIO


Esempio concreto di un applicazione react di un orologio che mostra l’ora attuale e dimostra la reattività di React:
L’applicazione e composta da 4 file:

file index.html
<div id="root"></div>
File html che contiene il tag root e rappresenta l’elemento padre del DOM in c0u65Zzzi gli verrà reindirizzata e
visualizzata tutta l’applicazione.

file Orologio.js
Questo file contiene il componente Orologio

import React from 'react';

function Orologio() {
  const oraMillisecondi = Date.now();
  const ora = new Date(oraMillisecondi);
    return (
        <p> {ora.toLocaleTimeString()}</p>
    )
}
export default Orologio;

Viene importata la libreria React, dopodichè viene creato il componente Orologio attraverso una function. Con
Date.now() si ottiene l’ora attuale in millisecondi, dopo si crea un oggetto di tipo Date. Il componente ritorna un
elemento p in cui riceve l’oggetto ora e toLocaleTimeString() lo visualizza in formato ore/min/sec. Infine viene
esportato il componente.

file App.js

import React from 'react';
import Orologio from './Orologio';

function App() {
  return (
    <div className ="App">
    <h1>Ora Attuale</h1>
    <Orologio/>
    </div>
  )
}

export default App;

è il componente padre di tutta l’applicazione, importa tutti i componenti figli, in questo caso solo il componente
Orologio e ritorna la struttura di tutti i componenti dell’applicazione.
Vediamo che importato il componente Orologio, questo può essere inserito nell’applicazione attraverso ad un
semplice tag <Orologio/>.
I tag dei componenti devono iniziare sempre con lettera maiuscola a differenza dei tag JSX.

file index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

function orario() {
  ReactDOM.render(<App/>, document.getElementById('root'));
}
setInterval(orario, 1000)

Questo importa React, ReactDOM, il file del componente padre App.


ReactDOM.render(componente, dove reindirizzarlo)
reindirizza il componente <App/> nella root del DOM nell’HTML. Questo componente mostra l’ora attuale in modo
statico, bisogna aggiornare la pagina per vedere gli aggiornamenti, per questo viene inserito il reindirizzamento
all’interno di una function che con setInterval() viene chiamata ogni secondo. Ad ogni chiamata della function,
reindirizzerà ogni secondo il componente e una caratteristica di React è che ad ogni reindirizzamento, viene
confrontato il DOM con quello precedente e cambieranno solo gli elementi che hanno subito modifiche. In questo
caso, tra tutti gli elementi, cambierà solo <p></p> , ogni secondo, il resto no.

PASSARE DA CLASSE A FUNCTION E VICEVERSA


Prima che venissero introdotti gli hook per gestire gli stati in react il codice veniva scritto con le classi. Introdotti gli
hooks si è passati dalle classi alle function e capita spesso di trovare ancora codice con le classi, ma la differenza tra
classi e function è minima e si può passare facilmente da una classe a una functione e viceversa.

Data la function:
function App() {
return (
     <div className="App">
       <header className="App-header">
         <img src={logo} className="App-logo" alt="logo" />
         <p> Prima App React </p>
      </header>
     </div>
   );
}

Per convertirla in una classe:


class App extends Component {
render() {
return (
     <div className="App">
       <header className="App-header">
         <img src={logo} className="App-logo" alt="logo" />
         <p> Prima App React </p>
      </header>
     </div>
   );
}
}

Importare import React, { Component } from 'react';
Si usa la keyword class, seguita dal nome, e si estende Component e si inserisce tutto il blocco di codice nel metodo
render() che viene chiamato ed eseguito automaticamente di default.

COMPONENTI E PROPS
I Componenti permettono di suddividere la UI in parti indipendenti e riutilizzabili . Concettualmente, i componenti
sono come funzioni JavaScript: accettano in input dati sotto il nome di “props” e ritornano elementi che descrivono
cosa dovrebbe apparire sullo schermo.
Props rappresenta un oggetto che contiene le proprietà di un componente.
Prendiamo l’esempio precedente dell’orologio e oltre all’ora attuale locale, inseriamo un altro componente orologio
che attraverso la props fusoorario mostra l’ora di 6 ore più avanti.
file App.js diventa:
function App() {
  return (
    <div className ="App">
    <h1>Ora Attuale</h1>
    <Orologio fusoorario = "0"/>
    <Orologio fusoorario = "6"/>
    </div>
  )
}

Vediamo che la props fusoorario viene passato al componente come un attributo del tag.

file Orologio.js diventa:


import React from 'react';

function Orologio(props) {
  const oraMillisecondi = Date.now() + props.fusoorario * 3600 * 1000;
  const ora = new Date(oraMillisecondi);
    return (
        <p> {ora.toLocaleTimeString()}</p>
    )
}
export default Orologio;

la function componente riceve come parametro props. All’ora attuale in millisecondi viene aggiunto il fusoorario
chiamato da props e convertito in millisecondi (* 3600 * 1000).

In un tag componente possono essere indicate quante props si vuole e richiamate poi nel componente (che riceve
come parametro sempre solo props) attraverso props.proprietà.

L’oggetto props è di sola lettura,non può essere modificato.

CLASSI E PROPS
Per richiamare ed utilizzare in una classe le proprietà props, prendiamo l’esempio dell’orologio convertito in classe:

file Orologio.js
import React from 'react';

class Orologio extends React.Component {
  constructor(props) {
    super(props);
  }
  render() {
  const oraMillisecondi = Date.now() + this.props.fusoorario * 3600 * 1000;
  const ora = new Date(oraMillisecondi);
    return (
        <p> {ora.toLocaleTimeString()}</p>
    )
    }
}

export default Orologio;

Possiamo estendere la classe sia con Component, importandolo in react, oppure semplicemente con
React.Component.
Per richiamare le props nella classe: si definisce il metodo constructor(), prima del metodo render(), ed in esso si
passa props, che si definisce poi nel metodo super().
Per utilizzare poi le props nella classe (nel metodo render()) si fa riferimento ad esse con:
this.props.proprietà

LO STATE DEI COMPONENTI


Fin ora, per aggiornare la UI, chiamiamo ReactDOM.render() per cambiare l’output renderizzato.
Lo state (o stato) è un oggetto dove vengono archiviati i valori che appartengono al componente e ogni volta che
lo state cambia il componente esegue nuovamente il rendering (viene chiamato automaticamente render()).
Lo state è simile alle props, ma è privato e completamente controllato dal componente.
Per gestire gli state sono necessari componenti di tipo classe, in modo che vengono incapsulati nel componente.
Lo state viene definito con la keyword state e va inizializzato nel constructor() della classe:
constructor() {
super();
this.state = { ... };
}
Riprendiamo l’esempio dell’Orologio, manca un requisito fondamentale: che il componente Orologio imposti un
timer ed aggiorni la propria UI ogni secondo nel suo interno. E poi avere:
ReactDOM.render(<Orologio/>, document.getElementById('root'));
Per implementare ciò, abbiamo bisogno di aggiungere uno “stato” al componente Orologio, che diventa:

import React from 'react';

class Orologio extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      orario: new Date()
    }
  }
  render() {
  const oraMillisecondi = this.state.orario.getTime() + this.props.fusoorario * 3600 * 1000;
  const ora = new Date(oraMillisecondi);
    return (
        <p> {ora.toLocaleTimeString()}</p>
    )
    }
}

export default Orologio;

Il metodo getTime() è un metodo dell’oggetto Date, uguale a now(), che ritorna l’ora attuale in millisecondi.
Questa classe viene reindirizzata con
ReactDOM.render(<App/>, document.getElementById('root'));
quindi per adesso ritorna l’ora in modo statico (non scorrono i secondi).

LIFECYCLE DEI COMPONENTI DI UNA CLASSE


Ogni componente React è caratterizzato da un Lifecycle (ciclo di vita) in cui possiamo distinguere tre fasi:
 Inizializzazione del componente (Mounting)
 Aggiornamento del componente (render) tramite setState() o la ricezione di nuove Props (Updating)
 Rimozione del componente (Unmounting)

Un componente, nel suo ciclo di vita, esegue in ordine alcuni metodi. Questi metodi hanno lo scopo di gestire il ciclo
di vita di un componente React e cominciano con will quando precedono un evento e con did quando seguono un
evento.

Abbiamo accesso a questi metodi che potremo usare per eseguire determinate azioni quando un componente viene
creato, aggiornato o distrutto o, addirittura, decidere se un componente deve essere modificato in seguito alla
variazione di almeno una delle proprietà contenute nel suo oggetto State o alla ricezione di nuove Props.
Inizializzazione di un componente (MOUNTING)

- Il costruttore è il primo metodo che viene chiamato per una corretta inizializzazione, verranno assegnati i valori di
default alle props definite tramite l'oggetto defaultProps e verrà quindi inizializzato l'oggetto state.
- Il secondo metodo ad essere invocato è componentWillMount() che viene chiamato prima che il componente
venga reindirizzato (metodo render).
React consiglia di usare il costruttore al posto di questo metodo per ogni inizializzazione.
- render() è l'unico metodo obbligatorio quando si vuole definire un componente. Deve restituire almeno un React
Element oppure null o false, se non vogliamo mostrare nulla sullo schermo per quel componente. Deve essere una
funzione pura, non deve modificare direttamente l'oggetto props o state.
- ComponentDidMount() é il metodo che viene invocato dopo eseguito il render(). Questo è il metodo da usare per
manipolare il DOM o per recuperare eventuali dati da un server.

Aggiornamento del componente (UPDATING)


Aggiornamento dell'oggetto State
Quando si effettua l'aggiornamento dell'oggetto State, vengono invocati una serie di metodi in sequenza.

-Il primo è shouldComponentUpdate() che riceve come argomenti gli oggetti nextProps e nextState che


rappresentano il prossimo valore dell'oggetto Props e dell'oggetto State e restituisce un valore booleano. Se false, i
metodi successivi non verranno invocati, di default restituisce true, consentendo l'aggiornamento del componente
ad ogni modifica degli oggetti State e Props. Per questo, può essere usato per determinare se il componente deve
essere aggiornato con i prossimi valori di Props e State. All'interno di questo metodo è possibile comparare i valori
attuali degli oggetti State e Props con quelli di nextState e nextProps, permettendo così di decidere se effettuare
l'aggiornamento del componente.
-Se shouldComponentUpdate() restituisce true, verrà invocato componentWillUpdate(). In questo metodo, non è
consentito modificare l'oggetto State tramite this.setState(), può essere utilizzato per preparare il componente
prima che avvenga l'aggiornamento dell'oggetto State o dell'oggetto Props.
-Dopo il metodo render(), viene invocato componentDidUpdate() che può essere usato per scaricare dati aggiornati
da un server o per operare sul DOM.

Ricezione di nuove Props


Anche nel caso in cui un componente riceva nuove Props, verranno invocati quasi gli stessi metodi nel caso
dell'oggetto State.
In questo caso abbiamo un metodo aggiuntivo: ComponentWillReceiveProps(), che non viene invocato in fase di
inizializzazione di un componente, ma successivamente, nel momento in cui nuove Props vengono passate a un
componente. Può essere utilizzato per aggiornare e modificare l'oggetto State all'interno di un componente se le
nuove Props ricevute sono diverse dalle proprietà dell'oggetto Props corrente.

Distruzione di un componente (UNMOUNTING)


Nella fase di smontaggio di un componente, verrà invocato come unico metodo componentWillUnmount() che può
essere usato per operazioni come invalidare eventuali timer avviati nella funzione componentDidMount() e altre
operazioni di manutenzione che prevengano memory leak.

AGGIUNGERE METODI LIFECYCLE AD UNA CLASSE


Nel nostro esempio, vogliamo impostare un timer ogni volta che Orologio è renderizzato nel DOM per la prima volta
(mounting). Vogliamo anche cancellare il timer ogni volta che il DOM prodotto da Orologio viene rimosso
(unmounting).
Il metodo componentDidMount() viene eseguito dopo che l’output del componente è stato renderizzato nel DOM. È
un buon punto in cui impostare un timer e implementiamo un metodo chiamato aggiornaTempo che verrà invocato
dal componente Orologio ogni secondo:

 componentDidMount() {
   this.time = setInterval(this.aggiornaTempo, 1000);
  }

Il metodo aggiornaTempo sarà:

aggiornaTempo = () => {
    this.setState( {
      orario : new Date()
    });
  }

Per effettuare un Update dello state si usa il metodo setState() che riceve le proprietà dello state che devono essere
aggiornate. In questo caso abbiamo la proprietà orario, ma se ce ne fossero state altre nell’oggetto this.state queste
non verrebbero prese in esame.
setState() fa un confronto tra le proprietà dell’oggetto che riceve con quelle di this.state e se sono state modificate,
le sovrascrive. Nel nostro caso viene semplicemente ridefinita la proprietà orario con un nuovo Date() più recente,
che setState() confronta con quello in this.state e lo sovrascrive.
In questo modo l’orologio scatta ogni secondo.
Ricapitoliamo cosa succede e l’ordine con cui i metodi sono invocati:
1 Quando <Orologio/> viene passato a ReactDOM.render(), React invoca il costruttore del componente che
inizializza this.state con un oggetto che include l’ora corrente. In seguito viene aggiornato questo state.
2 React invoca il metodo render() del componente Orologio e apprende cosa dovrebbe essere visualizzato sullo
schermo. React si occupa di aggiornare il DOM in modo da farlo corrispondere all’output di render.
3 Quando l’output della renderizzazione di Orologio viene inserito nel DOM, React invoca il metodo
componentDidMount(). Al suo interno, viene impostato un timer che invoca aggiornaTempo una volta al secondo.
4 Ogni secondo, al suo interno, il componente Orologio implemente un aggiornamento della UI
invocando setState() con un oggetto che contiene la nuova ora corrente. Con la chiamata a setState(), React viene
informato del fatto che lo state è cambiato e invoca di nuovo il metodo render() per sapere che cosa deve essere
mostrato sullo schermo. Questa volta, this.state.orario nel metodo render() avrà un valore differente e l’output della
renderizzazione includerà l’orario aggiornato. React aggiorna il DOM di conseguenza.

Se il componente Orologio dovesse essere rimosso dal DOM (UNMOUNTED), React invocherebbe il metodo


componentWillUnmount() ed è qui che dobbiamo cancellare il timer in modo da liberare le operazioni del
componente che è stato smontato nel DOM:

componentWillUnmount() {
   clearInterval(this.time);
  }

USO DI PROPS E STATE


Riassumendo, possiamo dire che:
 lo state: é un insieme di dati che modificati danno luogo a un aggiornamento del componente
stesso.
 Props: costituiscono valori immutabili per i quali non è prevista alcuna alterazione, utili per
configurare il componente o per indicare valori di default per lo stato.

GESTIONE EVENTI
Gli eventi React vengono dichiarati come per l’html, con la differenza che devono avere una sintassi:
camelCase = {this.metodo}
Prendiamo l’esempio dell’Orologio e inseriamo un bottone che stoppa e fa ripartire il tempo.
Bisogna gestire lo state del componente, e in esso inizializziamo una proprietà start:true:
   this.state = {
      orario: new Date(),
      start: true
    }
Dopodiche inseriamo nel return di render() un tag bottone:
<button>Stop</button>
Per gestire questo bottone, bisogna inserire un evento che chiami una function:
<button onClick={this.gestTime}>Stop</button>
Fin ora abbiamo implementato l’orologio in modo che una volta che il componente è montato nel DOM, parte
l’intervallo ogni secondo in componentDidMount() e lo smontiamo in componentWillUnmount().
In questo caso si deve gestire con l’evento e la function che chiama che se:
- l’orologio è stoppato, bisogna farlo ripartire;
- l’orologio NON è stoppato, bisogna stopparlo smontandolo.
Creiamo un metodo start(), con il setInterval(), e chiamiamo this.start() in componentDidMount().
Creiamo un metodo stop(), con clearInterval(), e chiamiamo this.stop() in componentWillUnmount().
Quando si definisce un componente classe, è comune usare un metodo della classe come gestore di eventi:

gestTime() {
    this.setState((state) => {
      state.start ? this.stop() : this.start(); 
  
     return {start: !state.start}; //state contrario
    })
  }
setState() riceve una function, che riceve come parametro lo state precedent e ritorna lo state contrario. Prima
verifica che se state è start chiama il metodo stop() per fermare l’orologio, altrimenti chiama il metodo start() per far
ripartire l’orologio.

binding
Il metodo precedente, però, in questo modo da ERRORE, in quanto non è possibile leggere setState(). Questo perchè
in JavaScript, i metodi delle classi non sono associati di default. Nel metodo gestTime il this appartiene al metodo
stesso, ma non fa riferimento alla classe, quindi bisogna fare il binding, ovvero associare il metodo alla classe.
Il binding va fatto nel constructor() con:
this.metodo = this.metodo.bind(this)
nel nostro caso:
this.gestTime = this.gestTime.bind(this);

ma se abbiamo molti metodi, bisogna scrivere questo per ogni metodo nel constructor(). Un altro modo equivalente
sta nel dichiarare il metodo come un arrow function:

gestTime = () => {
    this.setState((state) => {
      state.start ? this.stop() : this.start(); 
     return {start: !state.start};
    })
  }

Questo perchè, le arrow function non implementano il this, quindi in questo caso il this farà riferimento alla classe.

Se vogliamo un bottone dinamico che cambia in base allo state:


<button onClick = {this.gestTime}>{this.state.start ? 'STOP' : 'START'}</button>

La classe Orologio alla fine sarà:


import React from 'react';

class Orologio extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      orario: new Date(),
      start: true
    }
  }
  render() {
    const oraMillisecondi = this.state.orario.getTime() + this.props.fusoorario * 3600 * 1000;
    const ora = new Date(oraMillisecondi);
    return (
        <p>In {this.props.paese} {ora.toLocaleTimeString()}
           <button onClick = {this.gestTime}>{this.state.start ? 'STOP' : 'START'}</button>
        </p>
    )
    }

  aggiornaTempo = () => {
    this.setState( {
      orario : new Date()
    });
  }

  gestTime = () => {
    this.setState((state) => {
      state.start ? this.stop() : this.start(); 
  
     return {start: !state.start};
    })
  }
  
  start(){
    this.time = setInterval(this.aggiornaTempo, 1000);
  }
  stop(){
    clearInterval(this.time);
  }

  componentDidMount() {
    this.start();
  }

  componentWillUnmount() {
   this.stop();
  }

export default Orologio;

ARRAY DI ELEMENTI
Dato l’esempio di App.js:
. . .
        <Orologio paese = 'Italia' fusoorario = '0'/>
        <Orologio paese = 'Usa' fusoorario = '-6'/>
     . . .
vediamo che contiene solo due elementi <Orologio>, ma può capitare che in un componente ci siano molti elementi
dello stesso tipo e per questo possono essere gestiti in array di elementi ed essere implementati dinamicamente.
Nella classe o al di fuori di essa dichiariamo una variabile array const e in essa andiamo a inserire tanti oggetti quanti
sono gli elementi, che conterranno le props degli elementi. Per il nostro esempio:

const clocks = [
  {
    paese: 'Italia',
    fusoorario: 0
  },
  {
    paese: 'Usa',
    fusoorario: -6
  }
]

Ora per prendere i dati dall’array e implementare dinamicamente gli elementi <Orologio>, creiamo nel componente
classe un metodo che lo gestisce e ritornerà tanti elementi <Orologio> quanti sono gli elementi oggetti.

  getOrologi(){

    return clocks.map((clock) => {
      return <Orologio paese = {clock.paese} fusoorario = {clock.fusoorario}/>
    })
  }

Usiamo il metodo map() che esegue una function su ogni elemento che riceve dall’array che lo chiama (clocks).
Infine chiamiamo il metodo nel punto in cui devono essere elencati gli elementi, con:
{this.getOrologi()}
Iin questo modo, il metodo getOrologi() ritorna un errore, in quanto react, per ogni elemento di un array, si aspetta
un valore unico key. Tipo un ID che react usa per distinguere gli elementi, quindi o possiamo aggiungere un valore id
unico o usare un valore di cui siamo sicuri che sia unico per ogni elemento. Nel nostro esempio, possiamo usare la
proprietà paese come id:
  
getOrologi(){
  return clocks.map((clock) => {
    return <Orologio key = {clock.paese} paese = {clock.paese} fusoorario = {clock.fusoorario}/>
  })
}
Il file App.js alla fine sarà:
import React from 'react';
import Orologio from './Orologio';

const clocks = [
  {
    paese: 'Italia',
    fusoorario: 0
  },
  {
    paese: 'Usa',
    fusoorario: -6
  }
]

class App extends React.Component {
  
 getOrologi(){
   return clocks.map((clock) => {
    return <Orologio key = {clock.paese} paese = {clock.paese} fusoorario = {clock.fusoorario}/>
   })
 }

  render() {
  return (
    <div className="App">
        <h1>Ora Attuale</h1>
     {this.getOrologi()}
    </div>
  )
  }
}

export default App;

REACT ROUTER
React Router è una libreria che permette di creare applicazioni React con più pagine in cui la transizione fra una
pagina e l'altra avviene in maniera dinamica tramite Javascript, senza dover ogni volta ricaricare la pagina.
In React il Router non é altro che un componente che rotteizza altri componenti.

npm install --save react-router-dom

Nel file App.js importiamo due componenti: BrowserRouter, che rinominiamo per semplicità Router e Route.


import {BrowserRouter as Router, Route} from 'react-router-dom';
Avvolgiamo con l’ elemento <Router> tutto il componente e una serie di elementi <Route> racchiusi in un <div>.
Gli elementi <Route> hanno un attributo path che indica per quale URL deve essere mostrato un certo componente.
<Router>
<div>
<Route exact path="/" component={Home} />
<Route strict path="/team/" render={() => <h1>Team</h1>} />
</div>
</Router>

In Pratica Route legge la URL e in base ad essa reindirizza il componente.


Nel primo elemento <Route> abbiamo usato la proprietà exact ad indicare che dovrà essere mostrato il componente
Home solo se il valore dell'attributo path è uguale al valore della proprietà location.pathname. Se non avessimo
usato exact React Router avrebbe mostrato il componente Home anche per il path "/team”.
Nel secondo elemento <Route> abbiamo invece usato l'attributo strict che farà in modo che ci sia un match solo se
location.pathname è esattamente uguale a "/team/" ovvero solo se è presente la slash finale.
<Route> può anche ricevere altri attributi: component, render, children. In tutti e tre i casi verranno passate al
componente o alle funzioni (render e children) le proprietà history, location e match che sono degli oggetti.
La proprietà component specifica un componente che vogliamo venga mostrato in caso ci sia un match
( componente che deve essere mostrato per un certo valore di location.pathname).
Possiamo invece usare la prop render se vogliamo che venga invocata una certa funzione.
La prop children riceve anche una funzione che però verrà sempre eseguita.
I componenti <Link> e <NavLink>
Definite le rotte, con Route, vediamo come aggiungere link all'interno della applicazione per passare da una pagina
all'altra senza dover effettuare il refresh del browser, per fare questo, al posto dei tag <a href=""> (che fa chiamate
al server, ricaricando la pagina), dell HTML, usiamo due componenti, Link e NavLink.
Il componente Link accetta due attributi: to che può essere una stringa o un oggetto e replace. Per capire come
funziona quest'ultimo, dobbiamo considerare che React Router mantiene in memoria la cronologia delle pagine
visualizzate. Immaginiamo la cronologia come una pila, ogni volta che si visita una pagina, viene aggiunto un nuovo
elemento alla pila. Se l'attributo replace del componente Link è uguale a true, si sostituisce l'ultimo elemento della
pila invece di aggiungerne uno nuovo.

import React, {Component} from 'react';


import {Link} from 'react-router-dom';

class Team extends Component {


render() {
return (
<div>
<h1>Team</h1>
<Link to="/stagione">Stagione 2017</Link>
</div>
);
}
}

export default Team;

All'interno del componente Team, inseriamo un Link che porterà all'indirizzo localhost:3000/stagione e non verrà
ricaricata la pagina del browser.

NavLink è una versione particolare di Link. Esso può ricevere proprietá come activeClassName e activeStyle.
activeClassName=”nomeClasse” da uno stile quando un link é attivo.
Con activeStyle possiamo passare un oggetto attraverso il quale possiamo specificare lo stile che verrà applicato
all'elemento NavLink quando l'URL corrente è uguale al valore dell'attributo 'to' cioè quando location.pathname è
uguale al percorso specificato nell'attributo 'to'.

import React from 'react';


import {NavLink} from 'react-router-dom';

const Nav = () => (


<nav>
<NavLink exact activeClassName="current" to="/">Pagina Iniziale</NavLink>
<NavLink activeClassName="current" to="/team/">Team</NavLink>
<NavLink activeStyle={{color: 'green'}} to="/stagione/">Stagione</NavLink>
</nav>
);

export default Nav;


REDUX

React è una libreria di vista, e non è compito di React gestire specificamente lo stato.


Redux è “un contenitore di stati prevedibili per le applicazioni JavaScript”. In pratica è una architettura per la
gestione dello stato mediante passaggi chiari e ben definiti. Redux puó essere collegata con qualsiasi libreria
JavaScript, e non solo React. Redux consente di separare lo stato dell'applicazione da React

STATO DI UNA APPLICAZIONE


Lo stato è l’insieme delle condizioni interne o informazioni in uno specifico istante che determinano il risultato delle
interazioni con l’esterno. L'applicazione dispone di uno stato iniziale, e qualsiasi interazione dell'utente innesca
un'azione che aggiorna lo stato. Quando lo stato viene aggiornato, viene visualizzata la pagina.
La memorizzazione dei dati dell'applicazione nello stato di un componente va bene quando si dispone di
un'applicazione di base React con pochi componenti, ma la maggior parte delle applicazioni reali avrà molte più
caratteristiche e componenti. Quando aumenta il numero dei livelli nella gerarchia del componente, la gestione dello
stato diventa problematica ed é per questo che si usa Redux.
Spesso una applicazione si trova a dover gestire:
 dati provenienti dal server e memorizzati in una cache locale;
 dati generati dall’applicazione stessa che devono essere inviati al server;
 dati che devono rimanere in locale per rappresentare ad esempio la situazione corrente
dell’interfaccia utente o le preferenze espresse dall’utente.
La gestione di questi dati è complessa per la quantità e per il fatto che questi dati possono variare per cause diverse,
se poi consideriamo che queste modifiche possono avvenire in modo asincrono, diventa ancora piu complesso ed è
facile perdere il controllo sull’evoluzione dello stato.

FUNZIONE PURA
Una funzione pura è una normale funzione con due caratteristiche:
1 Dato un insieme di input, la funzione deve sempre restituire lo stesso output.
2 Non produce effetti collaterali.
Per esempio, una funzione é quella che restituisce la somma di due numeri.
Le funzioni pure danno un output stimabile e sono deterministiche. Una funzione diventa impura quando esegue
qualcosa di diverso dal calcolare il suo valore di ritorno.

I TRE PRINCIPI
La complessità nella gestione dello stato di un’applicazione sta nella  modificabilità e asincronicità. La soluzione di
Redux mira a rimuovere questi due aspetti, basandosi su tre principi fondamentali:
1 esiste una singola fonte di verità
lo stato dell’intera applicazione è memorizzato in un unico oggetto
2 lo stato è in sola lettura
non è possibile modificare direttamente le informazioni memorizzate nello stato dell’applicazione; solo
tramite azioni esplicite
3 le modifiche allo stato vanno fatte con funzioni pure
lo stato corrente viene sostituito da un nuovo stato generato da funzioni esclusivamente in base ad una
azione ed allo stato precedente
L’applicazione di questi principi definisce l’architettura di Redux e i vincoli che deve rispettare un’applicazione che
intende gestire lo stato secondo questo approccio.

VANTAGGI
Con Redux, le variazioni dello stato di un’applicazione risultano analizzabili e riproducibili, ed è più semplice
comprendere come si è arrivati ad una determinata situazione
Redux costringe ad organizzare il codice seguendo uno specifico pattern, il che definisce indirettamente uno
standard di codifica.
É possibile definire uno stato iniziale e far partire l’applicazione da quello stato, in questo modo da agevolare il
rendering di applicazioni JavaScript a partire dal server
É possibile tenere traccia delle transizioni di stato sia per il debugging che per implementare azioni.
INSTALLAZIONE
Se usiamo Node.js, possiamo installare Redux semplicemente con il seguente comando:
npm install --save redux
che scarica il pacchetto npm di Redux e lo rende disponibile per poter essere importato nella applicazione.
Se non utilizziamo un ambiente di sviluppo Node.js possiamo sempre la libreria scaricando la versione di
distribuzione del pacchetto npm ed inserendo un riferimento all’interno dalla pagina HTML della applicazione
<script src="redux.min.js"></script>
In questo caso Redux risulterà accessibile come una variabile globale window.Redux.

COMPONENTI CONTENITORE E COMPONENTI DI PRESENTAZIONE


É utile dividere l'architettura dei componenti in due categorie per le applicazioni React: componenti contenitore
(smart) e componenti di presentazione(dumb).
Il componente contenitore si occupa di come funzionano le cose, mentre i componenti di presentazione si occupano
di come appaiono le cose.
I componenti smart gestiscono lo stato e poi lo passano ai componenti dumb. Si prendono cura di effettuare le
chiamate alle API, recuperare i dati dalla sorgente dei dati, elaborare i dati e quindi impostare lo stato.
I componenti dumb ricevono i props e restituiscono la rappresentazione dell'interfaccia utente.
Quando state per scrivere un nuovo componente, non è sempre chiaro dove posizionare lo stato. Potreste lasciare
che lo stato sia parte di un contenitore che è un immediato genitore del componente di presentazione. Meglio
ancora, potete spostare lo stato più in alto nella gerarchia di modo che lo stato sia accessibile a componenti di
presentazione multipli.
Quando l'app cresce, lo stato è sparso ovunque. Quando un componente ha bisogno di accedere allo stato al quale
non ha immediatamente accesso, cercate di alzare lo stato fino al componente antenato più vicino.
É una buona idea lasciare che un componente nella parte superiore gestisca lo stato a livello globale e quindi passi
tutto verso il basso. Tutti gli altri componenti possono sottoscrivere i props di cui hanno bisogno e ignorare il resto.
Potete trattare tutti i componenti di React come dumb, cosí può concentrarsi solo sul lato vista delle cose.

ARCHITETTURA GENERALE DI REDUX


lo schema architetturale proposto dal modello Redux

Quindi il flusso generale per modificare lo stato corrente di un’applicazione segue i seguenti passi:
1 viene individuata una Action, eventualmente generata tramite un Action creator
2 tale Action viene inviata allo Store tramite un Dispatch
3 all’interno dello Store, un Reducer sostituisce allo stato corrente l’eventuale nuovo stato individuato
in base all’analisi della Action
Store
Lo store è un grande oggetto JavaScript che rappresenta lo stato corrente dell'applicazione, e ogni volta che lo stato
si aggiorna, la vista è rivisualizzata.
L'intero stato dell'applicazione è all'interno dell'oggetto store.
Lo store ha tre metodi per comunicare con il resto dell'architettura. Sono:
 Store.getState() per accedere all'albero dello stato corrente della applicazione.
 Store.dispatch(action) per innescare un cambiamento dello stato basato su un'azione.
 Store.subscribe(listener) per ascoltare qualsiasi cambiamento nello stato. Verrà chiamato ogni volta che
un'azione viene inviata.

Creare uno store.


Redux ha un metodo createStore per creare un nuovo store.
Riceve come parametri: un reducer e facoltativamente lo stato iniziale dello store.

index.js
import { createStore } from "redux";

const initialState = 0 //initialState (optional).


const store = createStore(reducer, initialState);

Ora ascolteremo eventuali modifiche nello store e poi con console.log() lo stato corrente dello store.
store.subscribe( () => {
console.log("State has changed" + store.getState());
})

Per aggiornare lo store Redux si usano le azioni.

Action/Action Creators
Le action sono semplici oggetti JavaScript che inviano informazioni dalla applicazione allo store. Se si dispone di un
semplice contatore con un pulsante di incremento, premendolo risulterà un'azione che viene attivata, che assomiglia
a questo:
{
type: "INCREMENT",
payload: 1
}

Lo stato dello store si modifica solo in risposta a un'azione. Ogni azione deve avere una proprietà di tipo (type) che
descrive ciò che intende fare l'azione.
É consigliato mantenete la azione piccola in quanto rappresenta la quantità minima di informazioni necessarie per
trasformare lo stato dell'applicazione.
Nell'esempio precedente, la proprietà type è impostata su "INCREMENT", ed è inclusa una ulteriore proprietà
payload che potrebbe essere rinominata in qualcosa di più significativo.

Per inviare l’action allo store si usa store.dispatch(action) :


store.dispatch({type: "INCREMENT", payload: 1});

Durante la scrittura di codice Redux, normalmente non si utilizzano le azioni direttamente, ma saranno chiamate le
funzioni che ritornano le azioni chiamate action creator.
L’action creator dell action precedente di incremento, sará:

const incrementCount = (count) => {


return {
type: "INCREMENT",
payload: count
}
}

Quindi, per aggiornare lo stato del contatore, è necessario spedire l'azione incrementCount così:


store.dispatch(incrementCount(1));
Ora, abbiamo bisogno dei reducer per convertire le informazioni fornite dall action e trasformare lo stato dello store.

Reducers
Il reducer (riduttore) utilizza le informazioni delle action per aggiornare effettivamente lo stato.
Un reducer dovrebbe essere una funzione pura. Dato un insieme di input, deve sempre restituire lo stesso output.
Oltre a ciò, non dovrebbe fare più nulla.
il reducer per il nostro contatore.

const reducer = (state = initialState, action) => {


switch (action.type) {
case "INCREMENT":
return state + action.payload
default:
return state
}
}

Il reducer riceve due argomenti stato e azione e restituisce un nuovo stato.


(previousState, action) => newState
Lo stato accetta un valore predefinito, initialState, che verrà utilizzato solo se il valore dello stato è
undefined. Altrimenti, verrà trattenuto il valore effettivo dello stato.
Usiamo lo switch per selezionare l’action giusta.
Aggiungiamo un case per DECREMENT:

const reducer = (state = initialState, action) => {


switch (action.type) {
case "INCREMENT":
return state + action.payload
case "DECREMENT":
return state - action.payload
default:
return state
}
}

Ecco l’action creator


const decrementCount = (count) => {
return {
type: "DECREMENT",
payload: count
}
}

Infine, viene inviato allo store.


store.dispatch(incrementCount(4)); //4
store.dispatch(decrementCount(2)); //2

REDUX E REACT

Abbiamo visto che con Redux inviamo le azioni e recuperiamo il nuovo stato utilizzando store.dispatch() e
store.getState().
Adesso imparareremo a collegare uno store Redux con React, con la libreria react-redux e vedremo
come:
1 organizzare i componenti contenitore e i componenti presentazione
2 come connettere react e redux utilizzando connect()
3 come spedire le azioni utilizzando mapDispatchToProps
4 come recuperare lo stato utilizzando mapStateToProps

1) Componenti Smart e componenti dumb


Un concetto giá discusso prima, di dividere in due cartelle distinte i componenti, uno
denominato containers e l'altro components. Il vantaggio di questo approccio è che la logica è separata
dalla vista.
I componenti smart, trattano la parte logica, passano i dati necessari per eseguire il rendering dei
componenti dumb come props.
Come primo passo, in un progetto, possiamo iniziare a creare tutta la parte grafica di React, ovvero i
componenti dumb e successivamente, da questi, creare i componenti smart per gestirne la logica

2) La libreria react-redux
Per collegare React a Redux sarà necessario installare una libreria supplementare chiamata react-redux.
npm install --save react-redux

La libreria esporta solo due API che è necessario ricordare, un componente <Provider/> e una funzione di
ordine superiore connect().

3) Il componente Provider
L'intera applicazione deve poter accedere allo store . Redux ha bisogno di rendere accessibile lo store dei
dati all'intero albero del componente react a partire dal componente principale. Il Provider consente di
passare i dati dall'alto verso il basso aggiungendo lo stato a tutti i componenti.

import { Provider } from 'react-redux'


 
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)

Avvolgiamo il provider intorno al componente dell'app e cosí i discendenti del componente hanno accesso
ai dati.

4) Il metodo connect()
Messo a disposizione lo store alla applicazione, abbiamo bisogno di collegare react con lo store. L'unico
modo in cui è possibile comunicare con lo store è inviando azioni e recuperando lo stato.
connect() permette appunto di collegare React con lo store, e con l'aiuto di due metodi:
mapDispatchToProps e mapStateToProps, di mappare e passare, solo le dispatch e la parte di store
interessati al componente dumb React come props.
 
const mapStateToProps = state => { const mapDispatchToProps = dispatch => {
return { return {
prop : state.prop dispatch : () => dispatch(actionCreator())
} }
} }

export default connect(


mapStateToProps,
mapDispatchToProps
)(ComponentDump)
mapStateToProps e mapDispatchToProps ritornano entrambi un oggetto e la chiave di questo oggetto
diventa un prop del componente collegato.
- MapStateToProps: collega una parte dello stato Redux alle props di un componente
React . In questo modo un componente React collegato avrà accesso alla parte esatta dello store
di cui ha bisogno .
- mapDispatchToProps fa qualcosa di simile, ma per le azioni: collega le azioni Redux alle props
React . In questo modo un componente React connesso sarà in grado di inviare messaggi allo
store.
Quindi é possibile utilizzare connect() per:
1 sottoscrivere lo store e mappare il suo stato al prop
2 inviare le azioni e mappare i callback di dispatch nei props
Una volta collegato l'applicazione a Redux, è possibile utilizzare this.props per accedere allo stato attuale
e anche spedire le azioni.
ESEMPIO REACT-REDUX: RUBRICA

Vediamo ora un esempio concreto di un'applicazione Rubrica telefonica con le seguenti caratteristiche:
 visualizzare tutti i contatti
 aggiungere un nuovo contatto
 rimuovere contatto

1) Struttura delle directory


Creato un nuovo progetto con create react app e installato Redux, Redux non ha idea di come strutturare la
applicazione, quindi il prossimo passo é aggiungere alcune directory vuote per organizzare Redux:

 components:  conterrá i componenti dumb di React, a cui non importa se si sta utilizzando Redux o meno.
 containers: conterrá i componenti smart di React che invia azioni allo store di Redux. L'associazione tra
redux e react si svolgerà qui.
 actions: conterrá gli action creators.
 reducers: ogni reducer ha un singolo file, questa directory conterrá tutta la logica dei reducers.
 store: conterrá la logica per l'inizializzazione dello stato e la configurazione dello store.

Questo modello di struttura é detto Rails e andrebbe bene applicazioni piccole e medie. Quando l’app cresce puo
essere piú comodo considerare il modello Dominio, dove ogni funzionalità avrà una directory per conto suo, e tutto
ciò che riguarda tale funzionalità sarà all'interno di essa.

2)Creare la parte della view con i componenti dump


Possiamo iniziare un progetto creando la parte React della view con i componenti dump. Possiamo utilizzare
Bootstrap per velocizzare il lavoro.
In questo progetto creiamo una applicazione con un menu con due voci che, con React Router, visualizzerá senza
ricaricare, le pagine della lista dei contatti e quella con il form per aggiungere un nuovo contatto.

3)Inizializzazione dello store


È una buona pratica abbozzare subito, anche su carta e penna, uno schema dello stato, in un singolo oggetto, con le
proprietá di cui ha bisogno.
Dopodiché nella directory Store, creiamo il file initialState.js ed inizializziamo lo store:

const initialState = {
contactList: [],
newContact: {
name: '',
email: '',
tel: ''
}
}

export default initialState;

Lo store ha due proprietá:  contactlist e newContact. contactlist è un array di contacts, mentre newContact é un


oggetto che conterrá temporaneamente i dati di contatto da aggiungere dal modulo di contatto.
4)Creazione dello store
Per creare lo store, nel file index.js, Importiamo createStore da redux:
import {createStore} from ‘redux’
questo crea lo store che conterrá l’albero dello stato.
Creiamo lo store con:
const store = createStore(rootReducer, initialiState);

Notiamo che esso riceve due parametri: il rootReducer e lo stato iniziale initialState (opzionale)
Importiamo initialState creato precedentemente.

Reducers multipli e combineReducers()


È importante ricordare che le funzioni Reducer non modificano l'oggetto State, ricevono in ingresso l'oggetto State
corrente e restituiscono un nuovo oggetto State e che un reducer deve avere sempre un valore predefinito per il suo
stato, e che deve sempre restituire qualcosa (default; return state).
Per loro é sempre consigliato creare una funzione Reducer per ogni pezzo dell'oggetto State e poi combinare tali
funzioni in un'unico Reducer, dividerli, invece di uno singolo, per migliorare la leggibilitá del codice.
Redux, per questo, ha un metodo denominato combineReducers() che consente di creare più reducer e poi di unirli
in una singola funzione (rootReducer).
Esso riceve come argomento l’oggetto avente come proprietá i reducers che creeremo:

export default combineReducers(


{
nome: reducer
}
);

I reducers creati, dovranno diventare le proprietà del combineReducers e per questo devono essere importati ed
inseriti con lo stesso nome della proprietà del pezzo di stato che riguardano

5)Creazione rootReducer
Questo sará il reducer principale che unirá in un unico reducer, tutti i reducer dell’applicazione.
Nella directory reducers, creiamo un file rootReducer.js, con combineReducers vuoto che unirá I reducers che
creeremo successivamente.

import { combineReducers } from 'redux'

export default combineReducers(


{

}
)
E una volta creato lo importiamo nel file index.js per passarlo al createStore.

6)Rendere lo store globale con Provider


Creato lo store, esso deve essere disponibile ed accessibile da tutta l’applicazione, in tutti i file. Per farlo e rendere lo
store globale:
importiamo il componente Provider da React Redux ed avvolgiamo il componente App con esso passandogli lo store

import { Provider } from 'react-redux'


 
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)

7)Gestire la logica e il funzionamento


Arrivati a questo punto analizziamo l’applicazione per gestirne la logica e il funzionamento vedendo quali
componenti dump necessitano di un accesso allo store, attraverso i componenti smart, e creando gli opportuni
actions e reducers.

Visualizzare i contatti dello store


Per visualizzare i contatti presenti nello store, creiamo un container detto contactListSmart dove con
mapStateToProps mappiamo la parte di state contactsList, con uno stesso nome contactsList
const mapStateToProps = (state) => {
return {
contactsList: state.contactsList
}
}

dopodiche’ con
export default connect(mapStateToProps, null)(ContactsList)

passiamo contactsLists come props al componente dumb ContactList (importato).


Il container deve essere esportato, perche’ dovra’ essere poi importato ed utilizzato in App.js al posto del
componente dumb ContactsList, per essere visualizzato.
In questo modo, il componente ContactsList ricevera’ come props solo la parte di state che gli serve.

Aggiungere nuovo contatto


creato il component con il form per l’aggiunta del nuovo contatto,
localStorage e sessionStorage: SALVARE I DATI NEL BROWSER

Un elemento che ci permette di salvare all’interno del browser informazioni rilevanti per la navigazione del sito, sono
i cookies. Ma il problema più grande dei cookies e’ che, per ricordarsi delle informazioni salvate, il browser deve
scambiarsi messaggi di stato con il server ad ogni nuova pagina che l’utente visita; questa caratteristica, sopratutto
nei siti dove è possibile prenotare viaggi o abitazioni, si traduce in un grande spreco di risorse che potevano essere
utilizzate per velocizzare il tempo di risposta dei siti web.
Grazie all’avvento dell' HTML5 sono stati introdotti due oggetti che ci permettono di salvare i dati passati dall’utente
all’interno dei propri browser: sessionStorage e localStorage.
Entrambi condividono le stesse proprietà e funzioni, le differenze tra i due sono che: il sessionStorage perderà tutti i
dati quando la finestra del browser verrà chiusa.
Mentre tutto quello che salviamo all’interno di un oggetto localStorage, sarà mantenuto dentro al browser e
resisterà anche allo spegnimento del computer.
All’interno di questi oggetti, possiamo salvare solo delle stringhe di testo, proprio come per i cookie, ma andando ad
utilizzare localStorage, o sessionStorage se soddisfano le necessità, non sarà necessaria alcuna comunicazione con il
server dato che la pagina web potra’ interrogare direttamente il browser.
Vediamo in specifico localStorage, ma sara’ lo stesso per sessionStorage.

Per la salvare un dato si utilizza la funzione setItem(“indice”, “valore”):

setItem() accetta due parametri. Il primo sarà l’indice e permetterà di richiamare successivamente il valore che
abbiamo impostato, il secondo è il valore vero e proprio che vogliamo salvare all’interno del browser.
Questi dati potranno essere poi visualizzati nell’ispeziona del browser

Salvati i dati, per recuperarli si usa la funzione getItem(“indice”):

Per rimuovere un dato salvato si usa la funzione removeItem( indice ) .


Altri parametri utili per lavorare con questo tipo di oggetti sono:
• length - permetterà di conoscere quanti elementi sono contenuti al suo interno, il suo indice parte da 0 come
per gli array;
• key( indice ) - inserendo il valore numerico dell’indice ci restituirà il valore salvato in questa posizione;
MIDDLEWARE
Finora abbiamo visto che il createStore riceve due parametri che sono il rootReducer e lo stato iniziale. Esso puo’
ricevere altri parametri che permettono di personalizzare o sostituire le azioni dello store (dispatch, subscribe,
getState).
Per personalizzare il comportamento di una dispatch si usa il middleware che è appunto una funzione eseguita tra il
dispatch di un’azione e la sua elaborazione da parte del reducer. In pratica intercetta le action e prende delle
decisioni in base a parametri: puo’ passare le action al reducer senza modifiche o fare a sua volta dispatch di action.

Vediamo che, l'action lanciata da store.dispatch() attraversa una serie di Middleware. Per far in modo che l'Action
venga inviata al Middleware successivo, o al Reducer nel caso dell'ultimo Middleware, bisogna invocare la funzione
next(action) che viene passata da Redux a ciascun Middleware.
In Redux sono particolarmente importanti perche rappresentano il punto dell'applicazione in cui e’ possibile fare
azioni asincrone come: chiamate API, timeout, ecc.
Una caratteristica importante, come si vede nell’immagine, e’ che possono essere inseriti piu’ middleware a catena
ed eseguiti nell’ordine un dopo l’altro.
Data una pila di middleware a catena, quando si effettua una dispatch, in pratica viene chiamato il primo
middleware. In genere un middleware verifichera’ se l’azione e’ di un type specifico che le interessa, simile a come
farebbe un reducer. Se e’ del type giusto, potrebbe eseguire una logica personalizzata, altrimenti passa l’action al
prossimo middleware nella pila.
A differenza di un reducer, un middleware puo’ avere effetti collaterali all’interno, includendo pause e altre logiche
asincrone.

Uso middleware
1)Definire la funzione middleware
Per usare i middleware in Redux, per prima cosa bisogna definire la funzione middleware, essa dovrà avere una precisa
segnatura.

// Middleware definito usando le arrow function


const mioMiddleware = store => next => action => {
// corpo della funzione Middleware
}

// o in maniera equivalente
function mioMiddleware(store) {
return function (next) {
return function (action) {
// corpo della funzione Middleware
};
};
};
All'interno del middleware abbiamo accesso all'Action lanciata da store.dispatch(action). Possiamo usare la funzione
next(action) per far scorrere l'Action lungo la catena dei middleware, invochera’ il prossimo middleware, se non
viene invocata la funzione, l'Action non viene passata al prossimo middleware.
All'interno di ogni middleware abbiamo accesso anche ai metodi store.getState() per recuperare l'oggetto State
corrente e store.dispatch() che è la funzione dispatch() originale. Utilizzando questa funzione, potremo far
ripercorrere all'oggetto action tutta la catena dei middleware già attraversati prima del middleware corrente.

2) Invocare la funzione applyMiddleware()


Dopo aver definito uno o più middleware, invochiamo la funzione applyMiddleware(...middleware) a cui passeremo
come argomento i middleware creati.
import { applyMiddleware} from 'redux';

Passeremo la funzione applyMiddleware al createStore.


const store = createStore(reducer, initialState, applyMiddleware(...middleware));

Riassumendo, i parametri store e action rappresentano rispettivamente lo store corrente e l’azione di cui stiamo


effettuato il dispatching. Il parametro next rappresenta il middleware successivo nella pipeline prima di arrivare
al reducer. In pratica, all’interno di un middleware possiamo sfruttare lo store e l’action correnti per effettuare
elaborazioni specifiche e passare poi la palla all’eventuale middleware successivo.
Vediamo un caso concreto di come può essere implementato un middleware per scrivere sulla console l’azione
intercettata e il nuovo stato dell’applicazione:

const logger = store => next => action => {


console.log('Azione corrente: ', action)
let result = next(action)
console.log('Stato successivo: ', store.getState())
return result
}

In questo caso specifico attendiamo l’esecuzione di eventuali middleware successivi prima di scrivere sulla console il
nuovo stato. Se non facessimo così otterremo lo stato corrente, invece del successivo.
Una volta definito il middleware lo rendiamo disponibile a Redux con

import { createStore, applyMiddleware } from 'redux'


let store = createStore(rootReducer, initialState, applyMiddleware(logger));

Questo farà sì che ogni transizione di stato verrà tracciata sulla console del browser:

Nel caso avessimo più middleware da eseguire prima del reducer, possiamo passarli come parametri della
funzione applyMiddleware() :

let middleware = applyMiddleware(middl1, middl2, middl3);

L’ordine di esecuzione dei middleware seguirà l’ordine con cui le funzioni vengono passate come parametro
ad applyMiddleware().
CHIAMATE ASINCRONE CON REACT REDUX
Vediamo ora come effettuare chiamate asincrone ad un server con React Redux.
Possiamo simulare un server locale con json-server, scaricabile da Npm, con i dati in json da servire. Una volta
installato, bisogna creare il file json da servire (db.json) e lanciare il server con:
json-server --watch db.json --port 3005 --nc
Adesso dobbiamo collegare la nostra app per leggere i dati da questo server.
Fin ora, abbiamo visto azioni sincrone dove l’oggetto payload con i dati, andava nello store, ma in questo caso i dati
si troveranno sul server e quindi bisogna fare una chiamata asincrona al server per prendere i dati.
Per gestire le chiamate asincrone, React utilizza i middleware, per facilitare il lavoro ci sono diversi package tra cui
redux-promise-middleware. Questo consente di gestire action creator asincroni, con la differenza che, in questo
caso, la payload riceve una promise:
const asyncAction = () => ({
type: ‘PROMISE’,
payload: new Promise(…)
})
Data una azione con un payload asincrono, il middleware trasforma l'azione in un'azione pending o un'azione
fulfilled/rejected, che rappresenta gli stati dell'azione asincrona.
Scaricato il package, nel index bisogna importarlo e passarlo allo store:

import promise from ‘redux-promise-middleware’


const store = createStore(rootReducer, initialState, applyMiddleware(promise));

Per dialogare con il server, usiamo il fetch(), o altri package, che appunto permette una gestione delle chiamate
asincrone basata sulle promise

REACT HOOKS
Sono stati introdotti con React 16.8 e in pratica sono funzioni che consentono di inserire uno stato hai componenti di
tipo function, più semplici di quelli di tipo classe.

useState()
Per aggiungere uno stato, ad un componente di tipo function, si usa useState che prima deve essere importata da
React. useState è una funzione che viene definita con:
const [variabile, setVariabile] = useState(initialValue);
ovvero, essa ritorna una coppia di valori: il valore dello stato corrente ed una funzione che permette di
aggiornarlo(dispach).
È simile a this.setState di una classe.
L’unico parametro di useState è il suo stato iniziale.

useEffect()
Dice a React che il componente deve fare qualcosa dopo il rendering. React ricorderà la funzione passata e la
chiamerà più tardi dopo aver eseguito gli aggiornamenti DOM, ad ogni modifica.  
Svolge gli stessi compiti di componentDidMount, componentDidUpdate, e componentWillUnmount .

Potrebbero piacerti anche