Sei interessato a imparare React? Ottieni il mio manuale React

React è una libreria JavaScript che mira a semplificare lo sviluppo di interfacce visive.

Sviluppato da Facebook e rilasciato pubblicamente nel 2013, è usato in alcuni dei codici più utilizzati al mondo. Alimenta Facebook e Instagram tra molte, molte altre società di software.

Il suo obiettivo principale è semplificare il ragionamento su un'interfaccia e sul suo stato in qualsiasi momento dividendo l'interfaccia utente in una raccolta di componenti.

React viene utilizzato per creare applicazioni Web a pagina singola, insieme a molte altre librerie e framework disponibili già prima che React prendesse vita.

Perché React è così popolare?

React ha preso d'assalto il mondo dello sviluppo web front end. Come mai?

Meno complesso delle alternative

Al momento dell'annuncio di React, Ember.js e Angular 1.x erano le scelte predominanti per i framework. Entrambi hanno imposto troppe convenzioni sul codice è ciò ha fatto si che il porting di un'app esistente non fosse affatto conveniente.

React è stato creato per essere molto facile da integrare in un progetto esistente. È così che hanno dovuto fare su Facebook per introdurlo nella codebase già esistente. Inoltre, questi due framework hanno portato troppo al tavolo, mentre React ha scelto solo di implementare il livello View invece dell'intero stack MVC.

Tempismo perfetto

Allo stesso tempo, Angular 2.x è stato annunciato da Google, insieme all'incompatibilità con le versioni precedenti e ai grandi cambiamenti che avrebbe portato. Passare da Angular 1 a 2 è stato come passare a un framework diverso. E quindi questo fatto, insieme ai miglioramenti della velocità di esecuzione che React prometteva, ha reso React qualcosa che gli sviluppatori erano ansiosi di provare.

Supportato da Facebook

Essere supportati da Facebook avvantaggia un progetto se si rivela un successo. Ma non è una garanzia, e ci sono molti progetti open source falliti sia da Facebook che da Google (tra gli altri).

React è davvero così semplice?

Anche se ho detto che React è più semplice dei framework alternativi, immergersi in React è comunque complesso. Ciò è dovuto principalmente alle tecnologie di contorno che possono essere integrate con React, come Redux, Relay o GraphQL.

React in sé ha un'API molto piccola.

Non c'è molto di più in React oltre a questi concetti:

  • Componenti
  • JSX
  • State
  • Props

Vedremo ognuno di loro nei miei prossimi paragrafi.

JSX

Molti sviluppatori, me compreso, a prima vista hanno pensato che JSX fosse orribile e hanno rapidamente respinto React.

Anche se dicevano che JSX non era richiesto, usare React senza JSX era penoso.

Mi ci sono voluti un paio d'anni per esaminarlo occasionalmente per iniziare a digerire JSX, e ora lo preferisco in gran parte all'alternativa (ovvero, usando i modelli).

Il principale vantaggio dell'utilizzo di JSX è che stai interagendo solo con oggetti JavaScript, non con modelli di stringhe.

JSX non è HTML incorporato.

Molti tutorial per i principianti di React preferiscono posticipare l'introduzione di JSX in un secondo momento, perché presumono che il lettore stia meglio senza di esso. Dato che ora sono un fan di JSX, tuttavia, ci entrerò immediatamente.

Ecco come definire un tag h1 contenente una stringa:

const element = <h1>Hello, world!</h1>

Sembra uno strano mix di JavaScript e HTML, ma in realtà è tutto JavaScript.

Quello che sembra HTML è in realtà fronzoli sintattici per definire i componenti e il loro posizionamento all'interno del markup.

All'interno di un'espressione JSX, gli attributi possono essere inseriti molto facilmente:

const myId = 'test' 
const element = <h1 id={myId}>Hello, world!</h1>

Devi solo prestare attenzione a quando un attributo ha un trattino (-), che viene invece convertito nella sintassi camelCase, nonché a questi due casi speciali:

  • class diventa className
  • for diventa htmlFor

perché sono parole riservate in JavaScript.

Ecco uno frammento di codice JSX che racchiude due componenti in un tag  div:

<div> 
  <BlogPostsList />
  <Sidebar /> 
</div>

Un tag deve sempre essere chiuso, perché questo è più XML che HTML (se ricordi i giorni XHTML, questo sarà familiare, ma da allora la sintassi libera di HTML5 ha vinto). In questo caso viene utilizzato un tag a chiusura automatica.

JSX, una volta introdotto con React, non è più una tecnologia solo di React.

Componenti di React

Che cos'è un componente React?

Un componente è un pezzo isolato dell'interfaccia. Ad esempio, in una tipica home page di un blog, potresti trovare il componente Barra laterale e il componente Elenco post del blog. Sono a loro volta composti dai componenti stessi, quindi potresti avere un elenco di componenti dei post del blog, ciascuno per ogni post del blog e ognuno con le sue proprietà peculiari.

Ok51aJciCr9ybh8lww0UL2Hl7g37lC2MJjne

React lo rende molto semplice: tutto è un componente.

Anche i semplici tag HTML sono componenti a sé stanti e vengono aggiunti per impostazione predefinita.

Le due righe successive sono equivalenti: fanno la stessa cosa. Uno con JSX , uno senza, iniettando <h1>Hello World!</h1> in un elemento con id app.

import React from 'react' 
import ReactDOM from 'react-dom' 

ReactDOM.render( 
  <h1>Hello World!</h1>, 
  document.getElementById('app') 
)

ReactDOM.render( 
  React.DOM.h1(null, "Hello World!"), 
  document.getElementById('app') 
)

Vedi, React.DOM espone per noi un componente h1. Quali altri tag HTML sono disponibili? Tutti quelli possibili! Puoi controllare cosa offre React.DOM digitandolo nella Console del browser:

9DaF1EtL86DXgUhe2wvb92sjYFLx6S5nxcIr

(l'elenco continua...)

I componenti integrati sono belli, ma li supererai rapidamente. Ciò in cui React eccelle è permetterci di comporre un'interfaccia utente componendo componenti personalizzati.

Componenti personalizzati

Ci sono 2 modi per definire un componente in React:

Un componente stateless non gestisce lo stato interno ed è solo una funzione:

const BlogPostExcerpt = () => {
 return (
    <div>
      <h1>Titolo</h1>
      <p>Descrizione</p>
    </div> 
  ) 
}

Un componente stateful è una classe, che gestisce lo stato nelle proprie proprietà:

import React, { Component } from 'react'

class BlogPostExcerpt extends Component { 
  render() { 
    return ( 
      <div>
        <h1>Titolo</h1> 
        <p>Descrizione</p> 
      </div> 
    ) 
  } 
}

Allo stato attuale, sono equivalenti perché non c'è ancora una gestione dello stato (cosa che vedremo nei prossimi paragrafi).

C'è una terza forma che usa la sintassi ES5/ES2015 senza le classi:

import React from 'react'

React.createClass({ 
  render() { 
    return ( 
      <div> 
        <h1>Titolo</h1>
        <p>Descrizione</p> 
      </div> 
    ) 
  } 
})

Raramente lo vedrai nelle moderne codebase > ES6.

Props è il modo in cui i componenti ottengono le loro proprietà. A partire dal componente superiore, ogni componente figlio riceve i suoi props dal genitore. In un componente stateless, props è tutto ciò che viene passato e sono accessibili aggiungendo props come argomento della funzione:

const BlogPostExcerpt = (props) => { 
  return ( 
    <div> 
      <h1>{props.titolo}</h1> 
      <p>{props.descrizione}</p> 
    </div> 
  ) 
}

In un componente stateful,  i props vengono passati per impostazione predefinita. Non è necessario aggiungere nulla di speciale e sono accessibili come this.props in un'istanza di Component.

import React, { Component } from 'react'

class BlogPostExcerpt extends Component { 
  render() { 
    return ( 
      <div>
        <h1>{this.props.titolo}</h1>  
        <p>{this.props.descrizione}</p> 
      </div> 
    ) 
  } 
}

PropTypes

Poiché JavaScript è un linguaggio tipizzato dinamicamente, non abbiamo davvero un modo per imporre il tipo di una variabile in fase di compilazione. Se passiamo tipi non validi, falliranno in fase di esecuzione o daranno risultati strani se i tipi sono compatibili ma non nel modo che ci aspettiamo.

Flow e TypeScript aiutano molto, ma React ha un modo per verificare direttamente i tipi di props. Anche prima di eseguire il codice, i nostri strumenti (editor, linter) possono rilevare quando stiamo passando i valori sbagliati:

import PropTypes from 'prop-types';
import React from 'react' 

class BlogPostExcerpt extends Component { 
  render() { 
    return ( 
      <div> 
        <h1>{this.props.titolo}</h1> 
        <p>{this.props.descrizione}</p> 
      </div> 
    ) 
  } 
}

BlogPostExcerpt.propTypes = { 
  titolo: PropTypes.string, 
  descrizione: PropTypes.string 
};

export default BlogPostExcerpt

Quali tipi possiamo usare

Questi sono i tipi fondamentali che possiamo accettare:

  • PropTypes.array
  • PropTypes.bool
  • PropTypes.func
  • PropTypes.number
  • PropTypes.object
  • PropTypes.string
  • PropTypes.symbol

Possiamo accettare uno di due tipi:

PropTypes.oneOfType([ PropTypes.string, PropTypes.number ]),

Possiamo accettare uno dei tanti valori:

PropTypes.oneOf(['Test1', 'Test2']),

Possiamo accettare un'istanza di una classe:

PropTypes.instanceOf(Qualcosa)

Possiamo accettare qualsiasi nodo React:

PropTypes.node

o anche di qualsiasi tipo:

PropTypes.any

Gli array hanno una sintassi speciale che possiamo usare per accettare un array di un tipo particolare:

PropTypes.arrayOf(PropTypes.string)

Possiamo comporre una proprietà di un oggetto usando:

PropTypes.shape({ 
  color: PropTypes.string, 
  fontSize: PropTypes.number 
})

Proprietà richieste

L'aggiunta di isRequired a qualsiasi opzione PropTypes farà sì che React restituisca un errore se quella proprietà è mancante:

PropTypes.arrayOf(PropTypes.string).isRequired, PropTypes.string.isRequired,

Valori predefiniti per i props

Se un valore non è richiesto, è necessario specificare un valore predefinito per esso se manca quando il componente viene inizializzato.

BlogPostExcerpt.propTypes = { 
  title: PropTypes.string, 
  description: PropTypes.string 
}

BlogPostExcerpt.defaultProps = { 
  titolo: '', 
  descrizione: '' 
}

Alcuni strumenti, come ESLint, hanno la capacità di imporre la definizione dei defaultProps per un Component con alcuni propType non esplicitamente richiesti.

Come vengono passati i props

Quando si inizializza un componente, si passa il props in un modo simile agli attributi HTML:

const desc = 'Una descrizione'
//...
<BlogPostExcerpt title="Un post del blog" descrizione={desc} />

Abbiamo passato il titolo come una semplice stringa (cosa che possiamo fare solo con le stringhe!), e la descrizione come una variabile.

Children

Un prop speciale è children. Questo contiene il valore di tutto ciò che viene passato nel componente body. Per esempio:

<BlogPostExcerpt title="Un post del blog" descrizione={desc}> 
  Qualcosa 
</BlogPostExcerpt>

In questo caso, all'interno BlogPostExcerpt potremmo accedere a “Qualcosa” tramite l'utilizzo di  this.props.children.

Mentre Props consente a un componente di ricevere proprietà dal suo genitore (potrebbero essere "istruito" per stampare alcuni dati, ad esempio), lo stato consente a un componente di assumere una vita propria ed essere indipendente dall'ambiente circostante.

Ricorda: solo i componenti basati sulla classe possono avere uno stato. Quindi, se devi gestire lo stato in un componente senza stato (basato su funzioni), devi prima "aggiornarlo" a un componente di classe:

const BlogPostExcerpt = () => { 
  return ( 
    <div>
      <h1>Titolo</h1>
      <p>Descrizione</p> 
    </div> 
  )
}

diventa:

import React, { Component } from 'react'

class BlogPostExcerpt extends Component { 
  render() { 
    return (
      <div>  
        <h1>Titolo</h1> 
        <p>Descrizione</p>
      </div>
    ) 
  } 
}

Impostazione dello stato predefinito

Nel costruttore del componente, inizializza this.state. Ad esempio, il componente BlogPostExcerpt potrebbe avere uno stato cliccato:

class BlogPostExcerpt extends Component {
  constructor(props) { 
    super(props) 
    this.state = { cliccato: false } 
  }

  render() { 
    return (
      <div> 
        <h1>Titolo</h1>
        <p>Descrizione</p> 
      </div> 
    ) 
  } 
}

Accesso allo stato

È possibile accedere allo stato cliccato facendo riferimento a this.state.cliccato:

class BlogPostExcerpt extends Component {
  constructor(props) { 
    super(props)
    this.state = { cliccato: false }
  }

  render() { 
    return (
      <div> 
        <h1>Title</h1> 
        <p>Descrizione</p> 
        <p>Cliccato: {this.state.cliccato}</p> 
      </div> 
    ) 
  } 
}

Mutarne lo stato

Uno stato non dovrebbe mai essere mutato usando

this.state.cliccato = true

Invece, dovresti sempre usare setState(), passandolo come oggetto:

this.setState({ cliccato: true })

L'oggetto può contenere un sottoinsieme o un superinsieme dello stato. Solo le proprietà che passi saranno mutate. Quelle omesse verranno lasciate nel loro stato attuale.

Perché dovresti sempre usare setState()

Il motivo è che utilizzando questo metodo, React sa che lo stato è cambiato. Inizierà quindi la serie di eventi che porteranno al nuovo rendering del componente, insieme a eventuali aggiornamenti DOM.

Lo stato è incapsulato

Un genitore di un Component non può dire se il figlio è stateful o stateless. Lo stesso vale per i figli di un Component.

Essere stateful o stateless (basato su classi o funzionale) è solo un dettaglio di implementazione di cui gli altri componenti non devono preoccuparsi.

Questo ci porta al flusso di dati unidirezionale

Flusso di dati unidirezionale

Uno stato è sempre di proprietà di un componente. Tutti i dati interessati da questo stato possono interessare solo i componenti sotto di esso: i suoi figli.

La modifica di uno stato su un componente non influirà mai sul suo genitore, sui suoi fratelli o su qualsiasi altro componente nell'applicazione, solo sui suoi figli.

Questo è il motivo per cui, molte volte, lo stato viene spostato in alto nell'albero dei componenti.

Spostare lo stato nell'albero

A causa delle regole del flusso di dati unidirezionale, se due componenti devono condividere uno stato, lo stato deve essere spostato su un predecessore comune.

Spesso, l'antenato più vicino è il posto migliore per gestire lo stato, ma non è una regola obbligatoria.

Lo stato viene trasmesso ai componenti che necessitano di quel valore tramite props:

class Converter extends React.Component { 
  constructor(props) { 
    super(props)
    this.state = { currency: '€' } 
  }

  render() { 
    return ( 
      <div> 
        <Display currency={this.state.currency} />
        <CurrencySwitcher currency={this.state.currency} />
      </div> 
    ) 
  } 
}

Lo stato può essere mutato da un componente figlio passando una funzione mutante come prop:

class Converter extends React.Component { 
  constructor(props) { 
    super(props) 
    this.state = { currency: '€' } 
  }

  handleChangeCurrency = (event) => { 
    this.setState({ 
      currency: this.state.currency === '€' ? '$' : '€' 
    }) 
  }

  render() { 
    return ( 
      <div> 
        <Display currency={this.state.currency} /> 
        <CurrencySwitcher currency={this.state.currency} handleChangeCurrency={this.handleChangeCurrency} /> 
      </div> 
    ) 
  } 
}

const CurrencySwitcher = (props) => { 
  return ( 
    <button onClick={props.handleChangeCurrency}> 
      Current currency is {props.currency}. Change it! 
    </button> 
  ) 
}

const Display = (props) => { 
  return ( 
    <p>Current currency is {props.currency}.</p> 
  ) 
}
W5hfnSrCoSOqkbTNbDn0b1bOocYiHkO70ZgB

Eventi

React fornisce un modo semplice per gestire gli eventi. Preparati a salutare addEventListener :)

Nel precedente articolo sullo Stato hai visto questo esempio:

const CurrencySwitcher = (props) => { 
  return ( 
    <button onClick={props.handleChangeCurrency}> 
      Current currency is {props.currency}. Change it! 
    </button> 
  ) 
}

Se usi JavaScript da un po', è proprio come i vecchi gestori di eventi JavaScript. Ma questa volta stai definendo tutto in JavaScript, non nel tuo HTML, e stai passando una funzione, non una stringa.

I nomi degli eventi effettivi sono leggermente diversi, perché in React usi camelCase per tutto. Così onclick diventa onClick, onsubmit diventa onSubmit.

Per riferimento, questo è l'HTML della vecchia scuola con eventi JavaScript aggiunti:

<button onclick="handleChangeCurrency()"> ... <;/button>

Gestori di eventi

È una convenzione avere gestori di eventi definiti come metodi sulla classe Component:

class Converter extends React.Component { handleChangeCurrency = (event) => { this.setState({ currency: this.state.currency === '€' ? '$' : '€' }) } }

Tutti i gestori ricevono un oggetto evento che aderisce, cross-browser, alla specifica W3C UI Events .

Vincola this nei metodi

Non dimenticare di associare i metodi. I metodi delle classi ES6 per impostazione predefinita non sono vincolati. Ciò significa che this non è definito a meno che tu non definisca i metodi come:

class Converter extends React.Component { 
  handleClick = (e) => { /* ... */ } 
  //... 
}

quando si utilizza la sintassi dell'inizializzatore della proprietà con Babel (abilitata per impostazione predefinita in create-react-app).

Altrimenti devi associarlo manualmente nel costruttore:

class Converter extends React.Component { 
  constructor(props) { 
    super(props); 
    this.handleClick = this.handleClick.bind(this); 
  }

  handleClick(e) {} 
}

Il riferimento agli eventi

Ci sono molti eventi supportati, quindi ecco un elenco di riepilogo.

Appunti

  • onCopy
  • onCut
  • onPaste

Composizione

  • onCompositionEnd
  • onCompositionStart
  • onCompositionUpdate

Tastiera

  • onKeyDown
  • onKeyPress
  • onKeyUp

Focus

  • onFocus
  • onBlur

Form

  • onChange
  • onInput
  • onSubmit

Mouse

  • onClick
  • onContextMenu
  • onDoubleClick
  • onDrag
  • onDragEnd
  • onDragEnter
  • onDragExit
  • onDragLeave
  • onDragOver
  • onDragStart
  • onDrop
  • onMouseDown
  • onMouseEnter
  • onMouseLeave
  • onMouseMove
  • onMouseOut
  • onMouseOver
  • onMouseUp

Selezione

  • onSelect

Touch

  • onTouchCancel
  • onTouchEnd
  • onTouchMove
  • onTouchStart

UI

  • onScroll

Rotellina del mouse

  • onWheel

Media

  • onAbort
  • onCanPlay
  • onCanPlayThrough
  • onDurationChange
  • onEmptied
  • onEncrypted
  • onEnded
  • onError
  • onLoadedData
  • onLoadedMetadata
  • onLoadStart
  • onPause
  • onPlay
  • onPlaying
  • onProgress
  • onRateChange
  • onSeeked
  • onSeeking
  • onStalled
  • onSuspend
  • onTimeUpdate
  • onVolumeChange
  • onWaiting

Immagine

  • onLoad
  • onError

Animation

  • onAnimationStart
  • onAnimationEnd
  • onAnimationIteration

Transizione

  • onTransitionEnd

Approccio dichiarativo di React

Ti imbatterai in articoli che descrivono React come un approccio dichiarativo alla creazione di interfacce utente .

Per ulteriori informazioni sulla programmazione dichiarativa, vedi programmazione dichiarativa.

Approccio dichiarativo di React

React ha reso il suo "approccio dichiarativo" piuttosto popolare e in primo piano, quindi ha permeato il mondo del front end insieme a React.

Non è davvero un concetto nuovo, ma React ha reso la creazione di interfacce utente molto più dichiarative rispetto ai modelli HTML. Puoi creare interfacce Web senza nemmeno toccare direttamente il DOM e puoi avere un sistema di eventi senza dover interagire con gli eventi DOM effettivi.

Ad esempio, la ricerca di elementi nel DOM utilizzando jQuery o eventi DOM è un approccio iterativo.

L'approccio dichiarativo di React lo astrae per noi. Diciamo semplicemente a React che vogliamo che un componente venga renderizzato in un modo specifico e non dobbiamo mai interagire con il DOM per farvi riferimento in seguito.

Il DOM virtuale

Molti framework esistenti, prima che React entrasse in scena, manipolavano direttamente il DOM su ogni modifica.

Il “vero” DOM

Che cos'è il DOM, prima di tutto? Il DOM ( Document Object Model ) è una rappresentazione ad albero della pagina, partendo dal tag <html> , scendendo in ciascuno dei figli, detti nodi.

È conservato nella memoria del browser e collegato direttamente a ciò che vedi in una pagina. Il DOM ha un'API che puoi utilizzare per attraversarlo, accedere a ogni singolo nodo, filtrarli e modificarli.

L'API è la sintassi familiare che probabilmente hai visto molte volte, se non stavi utilizzando l'API astratta fornita da jQuery e amici:

document.getElementById(id) 
document.getElementsByTagName(name) 
document.createElement(name) 
parentNode.appendChild(node) 
element.innerHTML 
element.style.left 
element.setAttribute()
element.getAttribute() 
element.addEventListener() 
window.content 
window.onload 
window.dump()
window.scrollTo()

React conserva una copia della rappresentazione DOM, perché il Virtual DOM riguarda il rendering di React.

Il DOM virtuale

Ogni volta che il DOM cambia, il browser deve eseguire due operazioni intensive: repaint (modifiche visive o di contenuto a un elemento che non influiscono sul layout e sul posizionamento rispetto ad altri elementi) e reflow (ricalcola il layout di una porzione della pagina — o l'intero layout di pagina).

React utilizza un DOM virtuale per aiutare il browser a utilizzare meno risorse quando è necessario apportare modifiche a una pagina.

Quando si chiama setState() su un Component, specificando uno stato diverso dal precedente, React contrassegna quel Component come sporco . Questa è la chiave: reagire solo agli aggiornamenti quando un componente cambia lo stato in modo esplicito.

Quello che succede dopo è:

  • React aggiorna il Virtual DOM relativo ai componenti contrassegnati come sporchi (con alcuni controlli aggiuntivi, come attivare shouldComponentUpdate())
  • Esegue l'algoritmo divergente per riconciliare le modifiche
  • Aggiorna il vero DOM

Perché il Virtual DOM è utile: batching

La cosa fondamentale è che React esegue in batch gran parte delle modifiche ed esegue un aggiornamento unico al vero DOM. Lo fa cambiando tutti gli elementi che devono essere modificati contemporaneamente, quindi il repaint e il reflow che il browser deve eseguire per attuare le modifiche, vengono eseguiti solo una volta.

Interessato a imparare React? Ottieni il mio manuale React