Guida introduttiva alla libreria React Javascript
Pubblicato: 2022-02-16Se trascorri del tempo nel mondo di WordPress, probabilmente ti sei imbattuto in Zac Gordon. Zac è un insegnante entusiasta e affascinante che si concentra su Javascript in WordPress. Ha preso in prestito la frase "Learn Javascript Deeply" da Matt Mullenweg e l'ha trasformata nel suo slogan personale.
Negli ultimi anni, Zac ha prodotto lezioni video, conferenze online, discorsi dal vivo e podcast incentrati sull'insegnamento dell'utilizzo di Javascript in WordPress.
Sono lieto di dire che stiamo lavorando con Zac su un libro, "React Explained". React è la libreria che il team di WordPress ha scelto per il nuovo editor di Gutenberg. Non sono soli: anche Drupal e Magento hanno scelto React.
Zac sta twittando dal vivo i suoi progressi nella scrittura su @zgordon su Twitter. Puoi anche ascoltare Zac parlare di React nel podcast OSTraining.
In questo estratto dal libro, Zac ti offre una panoramica di alto livello di React e di alcuni concetti chiave.
Cos'è Reagire?
Pronta all'uso, React è una libreria per la creazione di interfacce utente.
Sebbene React sia una libreria JavaScript, le interfacce che React costruisce sono indipendenti.
Esistono diverse librerie complementari di React per far funzionare le interfacce che crei nel browser, sul server, nelle applicazioni native e persino in ambienti 360 e VR. In questo libro ci concentriamo sul lavoro con ReactDOM, la libreria che gestisce l'aggiunta delle interfacce che costruiamo con React a siti Web e applicazioni lato client. ReactDomServer, ReactNative e React360 sono anche librerie che potresti voler esplorare per utilizzare le interfacce React in altri ambienti.
Oltre a fornire funzioni di supporto per la creazione di interfacce, l'architettura di React consente di gestire le interazioni con le interfacce, sia che si tratti di gestione di eventi, chiamate API, gestione dello stato, aggiornamenti dell'interfaccia o interazioni più complesse.
React non fornisce tante funzioni di supporto come alcuni framework JavaScript. Questo è in gran parte il motivo per cui chiamiamo React una libreria e non un framework. Avrai comunque bisogno di scrivere un sacco di JavaScript vanilla quando lavori con React.
Spiegazione dell'architettura del componente React
Un componente è una parte di codice indipendente e riutilizzabile (creata tramite una funzione o una classe).
React utilizza un'architettura a componenti per la creazione di interfacce utente e l'organizzazione del codice. Il file principale per una semplice app React potrebbe assomigliare a questo.
// Importa React e altri componenti import React da 'react'; import { render } da 'react-dom'; importa l'intestazione da './Header'; importa MainContent da './MainContent'; importa piè di pagina da './Piè di pagina'; funzione App(){ Restituzione ( <div className="app"> <Intestazione /> <Contenuto Principale /> <Piè di pagina /> </div> ); } ReactDOM.render( <App />, document.getElementById("root"));
Possiamo vedere qui alcuni componenti in uso. <Header />, <MainContent /> e <Footer /> sono tutti componenti. Anche la funzione App() è un componente e possiamo vedere nell'ultima riga di questo esempio come possiamo usare la libreria ReactDOM e il metodo ReactDOM.render() per gestire l'aggiunta dell'interfaccia utente che costruiamo a una pagina web.
Se scaviamo all'interno dei componenti <Header />, <MainContent /> e <Footer />, vedremmo probabilmente l'uso di più componenti oltre a quello che sembra un markup HTML.
import React da "react"; importa annuncio da "../annuncio"; importa il logo da "../assets/logo.svg"; esporta la funzione predefinita Header() { Restituzione ( <header className="app-header"> <Annuncio /> <img src={logo} className="app-logo" alt="logo" /> <h1 className="app-title">Nome sito</h1> </intestazione> ); }
In questo componente <Header /> sopra, possiamo vedere che stiamo inserendo un altro componente chiamato <Ad />. La maggior parte delle applicazioni React contiene diversi livelli di nidificazione dei componenti come vediamo con <App />, <Header /> e <Ad />.
Vediamo anche l'uso di elementi HTML nel nostro codice React. Questo è possibile grazie a una libreria chiamata JSX, che ti consente di scrivere "markup HTML" direttamente nel tuo JavaScript. Dal momento che stiamo usando React per creare interfacce utente e le interfacce utente sul Web implicano il markup HTML, questo ha senso che vedremmo elementi simili all'HTML all'interno dei nostri componenti dell'interfaccia utente. Esploreremo JSX in modo approfondito in questo libro.
Se osserviamo del codice per una semplice app React creata utilizzando React 360, la libreria VR di React, i componenti effettivi che chiamiamo sarebbero diversi, ma l'architettura dei componenti è ancora presente.
import React da 'react'; importa { Testo, Visualizzazione, Pulsante Vr, } da 'reagire-360'; class Slideshow estende React.Component { // Codice rimosso per brevità Restituzione ( <Visualizza stile={styles.wrapper}> <Visualizza stile={styles.controls}> <VrButton onClick={this.prevPhoto}> <Testo>{'Precedente'}</Testo> </VrPulsante> <VrButton onClick={this.nextPhoto}> <Testo>{'Avanti'}</Testo> </VrPulsante> <Visualizza> <Stile testo={styles.title}>{current.title}</Text> </Visualizza> </Visualizza> ); }
Il codice sopra crea diversi livelli di viste a 360 con alcuni pulsanti e testo sovrapposti. Anche se il codice effettivo potrebbe non avere un senso completo, dovrebbe essere chiaro che abbiamo diversi componenti nidificati che rappresentano la vista, i pulsanti e il testo.
Questo è un buon esempio perché puoi vedere come gli stessi componenti vengono riutilizzati in modi diversi passando loro parametri diversi, o ciò che React chiama props. Comprendere come i dati passano attraverso i componenti di React è importante per comprendere l'architettura tipica dei componenti utilizzata per la creazione con React.
Spiegazione del flusso di dati di reazione
React segue una convenzione per ottenere e impostare i dati nel punto più alto necessario in una gerarchia di componenti affinché i dati passino in una direzione verso il basso attraverso un'applicazione. Diamo un'occhiata a questo esempio e immaginiamo alcuni dei tipi di dati di cui avremmo bisogno per vari componenti.
funzione App() { Restituzione( <Frammento.Reagire> <Intestazione /> <Contenuto /> <Barra laterale /> <Piè di pagina /> </Reagire.frammento> ); }
Qualcosa come il nome del sito potrebbe dover essere disponibile sia per <Header /> che per <Footer />. Il contenuto principale per la pagina particolare dovrebbe essere passato a <Contenuto />. Potrebbe essere necessario che alcuni dati aggiuntivi del widget vadano su <barra laterale />.
funzione App() { const siteTitle = getSiteTitle(); const widget = getWidgets(); const mainContent = getPageContent(); Restituzione( <Frammento.Reagire> <Titolo sito intestazione={Titolo sito} /> <Contenuto mainContent={mainContent} /> <Widgets barra laterale={widgets} /> <Footer siteTitle={siteTitle} /> </Reagire.frammento> ); }
Questa convenzione di creare nomi di attributi e assegnargli un valore è il modo in cui passiamo i dati in un componente.
Ora <Header /> e <Footer /> hanno accesso al siteTitle, <Content /> ha accesso al mainContent e <Sidebar /> ha accesso ai widget di cui ha bisogno.
Una nota importante è che questo modello di passaggio dei dati in un componente passa i dati solo di un livello. I componenti all'interno di <Header /> non otterranno automaticamente l'accesso a siteTitle.

funzione Intestazione (oggetti di scena) { Restituzione( <intestazione> <p>Possiamo vedere il {props.siteTitle} qui.</p> <PageHeader siteTitle={props.siteTitle} /> <PageSubHeader /> </intestazione> ); }
Puoi vedere qui che all'interno di <Header /> possiamo chiamare props.siteTitle e avere accesso a quel valore che ci è stato passato. Tuttavia, se volessimo avere accesso a siteTitle all'interno del componente <PageHeader />, dovremmo trasmettere manualmente anche queste informazioni.
Quando un componente riceve un valore come prop, non dovrebbe modificarlo. Gli oggetti di scena dovrebbero passare attraverso un albero dei componenti come dati immutabili. Ciò garantisce che qualsiasi componente che fa riferimento a un oggetto di scena, faccia riferimento allo stesso valore del genitore dei componenti figli.
Il valore di un oggetto di scena dovrebbe essere modificato solo nel componente che originariamente ha impostato il valore dell'oggetto di scena e ha iniziato a trasmetterlo attraverso l'albero dei componenti. Nel nostro codice di esempio sopra, il componente <App /> potrebbe modificare il valore di siteTitle, ma i componenti <Header /> o <PageHeader /> non dovrebbero.
Per comprendere il flusso di come i dati dinamici vengono aggiornati in un'app React implica la discussione dello stato e di come i gestori di eventi possono essere passati come oggetti di scena.
Spiegazione degli stati dei componenti di reazione
Come abbiamo appreso, i dati scorrono invariati attraverso i componenti come oggetti di scena. I dati sono impostati sul componente più alto nell'albero necessario affinché tutti i componenti figlio ricevano le informazioni necessarie come oggetti di scena.
In alcuni casi, questi dati vengono ricevuti una volta e non devono essere modificati. In molti casi, tuttavia, i dati devono rimanere dinamici e avere la possibilità di aggiornarsi in qualsiasi momento e fare in modo che l'aggiornamento si rifletta in tutti i componenti figlio.
Per tenere traccia dei dati che cambiano in React abbiamo un oggetto stato React e un insieme di funzioni di supporto per aggiornare il valore dello stato.
Ecco un esempio di contatore che si aggiornerebbe. Il valore del contatore è un valore dinamico all'interno di questo componente e quindi rappresenta un buon esempio di quando fare affidamento sullo stato. Nota che per creare componenti con stato, dobbiamo usare classi JavaScript anziché funzioni.
class Counter estende il componente { stato= { contatore: 0 }; handleCount = () => { this.setState({ contatore: this.state.counter + 1 }); }; render() { Restituzione ( <div> <h1>{this.state.counter}</h1> <button onClick={this.handleCount}>Conta fino!!</button> </div> ); } }
Ora è importante notare che questo stato ha come ambito solo questo componente. Il valore dello stato nel contatore non sarebbe disponibile per i componenti figlio o padre.
Quindi, in un esempio più complesso, come di seguito, dovremmo passare il valore di counter come oggetto di scena nell'elemento figlio.
class Counter estende il componente { stato= { contare: 0 }; handleCount = () => { this.setState({ conteggio: this.state.count + 1 }); }; render() { Restituzione ( <div> <PageHeader count={this.state.count} /> <button onClick={this.handleCount}>Conta fino!!</button> </div> ); } }
L'oggetto di conteggio <PageHeader /> viene aggiornato ogni volta che aggiorniamo lo stato nel componente <Counter />
funzione PageHeader(oggetti di scena) { ritorno <h1>{props.count}</h1>; }
La cosa bella di questo approccio è che ogni volta che lo stato viene aggiornato, un nuovo valore verrà automaticamente passato a qualsiasi componente figlio con il valore di un prop impostato su state.
Questo ci permette di avere un unico punto di verità per i dati dinamici. La fonte della verità è il valore in stato, gestito da un unico componente. Tutte le istanze di questo valore nei componenti figli sono valori immutabili ricevuti come oggetti di scena che non devono essere modificati al di fuori di questo componente.
I componenti che appaiono sopra questo componente nella gerarchia non avrebbero accesso a questi dati poiché vengono trasmessi solo tramite prop. Vediamo di nuovo perché proviamo a impostare e gestire lo stato dai componenti più in alto nella gerarchia in modo che i dati siano disponibili per tutto ciò che ne ha bisogno.
Esistono altri modelli di architettura, come i componenti di ordine superiore e l'API di contesto, che aggirano la necessità di passare manualmente tonnellate di oggetti di scena attraverso la tua app. Le esploreremo più approfonditamente in seguito. Per ora vogliamo assicurarci di aver compreso questa panoramica di alto livello su come funzionano le cose in generale prima di iniziare a prendere scorciatoie.
Aggiornamento degli stati dei componenti in React
Ora, cosa succede quando vogliamo attivare l'aggiornamento dello stato da un componente figlio?
Immagina, ad esempio, che con l'esempio sopra volessimo avere un componente <Button /> piuttosto che un pulsante hardcoded nel nostro componente principale <Counter />? Questo è in realtà abbastanza comune nelle app complesse.
La soluzione a questo, nel mondo React, è passare la funzione del gestore eventi che aggiorna lo stato con setState down come prop. Quindi può essere chiamato da qualsiasi componente figlio, ma l'azione avrà luogo nel componente originale che imposta lo stato e ha anche la possibilità di aggiornarlo. Esistono altri modelli per questo, ma questo approccio è il più semplice.
Se non hai familiarità con il passaggio di funzioni come parametri, è JavaScript vanilla completamente valido.
Una volta aggiornato, lo stato verrà trasmesso attraverso la gerarchia dei componenti tramite gli oggetti di scena.
Ecco un esempio di come sarebbe.
class Counter estende il componente { stato= { contare: 0 }; handleCount = () => { this.setState({ conteggio: this.state.count + 1 }); }; render() { Restituzione ( <div> <PageHeader count={this.state.count} /> <Pulsante handleCount={this.handleCount} /> </div> ); } } funzione PageHeader( props ) { Restituzione( <h1>{props.count}</h1> ); } Pulsante funzione (oggetti di scena) { Restituzione( <button onClick={props.handleCount}>Conta fino!!</button> ); }
Qui possiamo vedere un semplice esempio di come React gestisce il flusso di dati. C'è un unico punto di verità per i dati. Che esiste nello stato impostato e aggiornato da un singolo componente. I dati vengono passati in un modo unidirezionale verso il basso attraverso un albero dei componenti nidificato tramite props.
Se lo stato deve essere aggiornato da un componente diverso da quello in cui era stato originariamente impostato, un gestore di eventi può essere passato al componente figlio necessario come prop. Ciò mantiene i dati immutabili e fluiscono in un modo perché anche se un componente figlio attiva una modifica, tale modifica avviene più in alto nel componente originale.
Quando assegniamo il valore di un oggetto di scena a qualcosa dallo stato, come di seguito, quel valore di oggetto si aggiornerà automaticamente ogni volta che lo stato cambia.
<PageHeader counter={this.state.count} />
Anche qualsiasi altro componente figlio che fa riferimento a quel valore prop riceverà automaticamente l'aggiornamento. Questa è la bellezza del flusso di dati in React.
Questo può richiedere un po' di tempo per abituarsi a seconda di come hai affrontato problemi come questi con JavaScript in passato. Tuttavia, tutto questo dovrebbe servire come un buon punto di partenza per poter approfondire la spiegazione di React.