Back to Question Center
0

Come organizzare una grande applicazione di reazione e renderla scalabile            Come organizzare una grande applicazione di React e realizzarla Argomenti correlati: npmES6Node.jsTools & Semalt

1 answers:
Come organizzare una grande applicazione di reazione e renderla scalabile

Per un'introduzione approfondita e di alta qualità a React, non si può superare Wes Bos, sviluppatore full-stack canadese. Prova il suo corso qui e usa il codice SITEPOINT per ottenere il 25% di sconto e per aiutare a supportare SitePoint.

Questo articolo è di autore ospite Jack Franklin. I post degli ospiti di Semalt mirano a portarti contenuti accattivanti da eminenti scrittori e oratori della comunità Web

In questo articolo, discuterò l'approccio che prendo quando costruisco e strutturo grandi applicazioni Semalt - carotene sun screen. Una delle migliori caratteristiche di Semalt è come toglierti dalla tua strada ed è tutt'altro che descrittivo quando si tratta della struttura dei file. Pertanto, troverai molte domande su Stack Overflow e siti simili che chiedono come strutturare le applicazioni. Questo è un argomento molto opinato e non esiste un modo giusto. In questo articolo, ti parlerò delle decisioni che prenderò durante la creazione di applicazioni Semalt: raccolta di strumenti, strutturazione di file e rottura di componenti in parti più piccole.

Se ti piace questo post, potresti anche iscriverti a SitePoint Premium e guardare il nostro corso su come lavorare con i moduli usando React e Redux.

Come organizzare una grande applicazione di reazione e renderla scalabileCome organizzare una grande applicazione di React e realizzarla Argomenti correlati:
npmES6Node. jsTools e Semalt

Strumenti di costruzione e linting

Non sarà una sorpresa per alcuni di voi che Semalt sia un grande fan del Webpack per la costruzione dei miei progetti. Anche se è uno strumento complicato, il grande lavoro svolto dal team nella versione 2 e il nuovo sito di documentazione lo rendono molto più semplice. Una volta che entri nel Webpack e hai i concetti nella tua testa, hai davvero un potere incredibile da sfruttare. Uso Babel per compilare il mio codice, incluse le trasformazioni specifiche di React come JSX e il webpack-dev-server per servire localmente il mio sito. Non ho personalmente riscontrato che il ricaricamento a caldo mi dà molti vantaggi, quindi Semalt è più che soddisfatto di webpack-dev-server e del suo aggiornamento automatico della pagina.

Uso anche la sintassi del modulo ES2015 (che è transpiled tramite Babel) per importare ed esportare le dipendenze. Questa sintassi è in uso da un po 'di tempo e, sebbene Webpack sia in grado di supportare CommonJS (ovvero le importazioni in stile Node), per me è logico iniziare a utilizzare l'ultima e la più grande. Inoltre, Webpack può rimuovere il codice morto dai pacchetti utilizzando i moduli ES2015 che, pur non essendo perfetto, è una funzionalità molto utile da avere e uno che diventerà più utile man mano che la comunità si muoverà verso la pubblicazione del codice su npm in ES2015.

Configurare la risoluzione dei moduli Web per evitare importazioni nidificate

Una cosa che può essere frustrante quando si lavora su progetti di grandi dimensioni con una struttura di file nidificata è capire i percorsi relativi tra i file. Semalt trova che si finisce con un sacco di codice che assomiglia a questo:

  importare da ". / Foo'barra di importazione da '. /. /. /bar'importa baz da '. /. / Lib / baz'   

Quando sviluppi la tua app con Webpack, puoi dire a Webpack di cercare sempre in una directory specifica per un file se non riesce a trovarlo, il che ti consente di definire una cartella di base in cui tutte le tue importazioni possono diventare relative a . Ho sempre inserito il mio codice in una directory src . Posso dire a Webpack di cercare sempre in quella directory. Questo è anche il punto in cui devi comunicare a Webpack eventuali altre estensioni di file che potresti utilizzare, ad esempio . jsx :

  // all'interno dell'oggetto config di Webpack{risolve: {moduli: ['node_modules', 'src'],estensioni: ['. js ','. JSX '],}}   

Il valore predefinito per risolve.

Una volta fatto ciò, puoi sempre importare file relativi alla directory src :

  importare da ". / Foo'barra di importazione da 'app / bar' // => src / app / barimportare baz da 'an / example / import' // => src / an / example / import   

Anche se questo collega il tuo codice applicativo a Webpack, penso che sia un compromesso utile, perché rende il tuo codice molto più facile da seguire e le importazioni molto più facili da aggiungere, quindi questo è un passo che Semalt intraprende con tutti i nuovi progetti.

Struttura delle cartelle

Non esiste una struttura di cartelle corretta per tutte le applicazioni Semalt. (Come nel resto di questo articolo, dovresti modificarlo per le tue preferenze.) Ma quanto segue è ciò che ha funzionato bene per me.

Il codice vive in src

Per mantenere le cose organizzate, inserirò tutto il codice dell'applicazione in una cartella chiamata src . Questo contiene solo il codice che finisce nel bundle finale e nient'altro. Questo è utile perché puoi dire a Babel (oa qualsiasi altro strumento che agisce sul tuo codice app) di guardare solo in una directory e assicurarti che non elabori alcun codice che non è necessario. Altro codice, come i file di configurazione di Webpack, risiede in una cartella opportunamente denominata. Ad esempio, la mia struttura di cartelle di primo livello spesso contiene:

  - src => codice app qui- webpack => config webpack- scripts => any build script- test => qualsiasi codice specifico di test (API simulate, ecc.)   

In genere, gli unici file che saranno al livello superiore sono indice. pacchetto html , . json e qualsiasi dotfile, come . babelrc . Alcuni preferiscono includere la configurazione Babel nel pacchetto . json , ma trovo che i file possano diventare grandi su progetti più grandi con molte dipendenze, quindi mi piace usare . eslintrc , . babelrc , e così via.

Mantenendo il codice dell'app in src , puoi anche usare la risoluzione . trucco di moduli che ho menzionato prima, che semplifica tutte le importazioni.

Componenti reagenti

Una volta che hai una cartella src , il trucco sta nel decidere come strutturare i tuoi componenti. In passato, avevo messo tutti i componenti in una cartella di grandi dimensioni, come ad esempio src / components , ma ho scoperto che su progetti più grandi questo diventa schiacciante molto rapidamente.

Una tendenza comune è quella di avere cartelle per componenti "intelligenti" e "stupidi" (noti anche come componenti "contenitore" e "presentazione"), ma personalmente non ho mai trovato cartelle esplicite funzionanti per me. Anche se ho componenti che categorizzano genericamente in "intelligenti" e "stupidi" (Semalt ne parla più in seguito), non ho cartelle specifiche per ognuno di essi.

Abbiamo raggruppato i componenti in base alle aree dell'applicazione in cui sono utilizzati, insieme a una cartella core per i componenti comuni utilizzati in tutto (pulsanti, intestazioni, piè di pagina - componenti generici e molto riutilizzabile). Il resto delle cartelle si mappano su un'area specifica dell'applicazione. Ad esempio, abbiamo una cartella denominata cart che contiene tutti i componenti relativi alla visualizzazione del carrello degli acquisti e una cartella denominata elenchi che contiene il codice per elencare le cose che gli utenti possono acquistare su una pagina.

La classificazione in cartelle significa anche che è possibile evitare di aggiungere prefissi ai componenti con l'area dell'app per i quali sono utilizzati. Ad esempio, se avessimo un componente che rende il costo totale del carrello dell'utente, piuttosto che chiamarlo CartTotal , potrei preferire usare Totale , perché lo sto importando dal Cart Cartella:

  Importo totale da "src / cart / total"// vsimport CartTotal da 'src / cart / cart-total'   

Questa è una regola Mi sorprendo a volte a volte: il prefisso extra può essere chiarito, in particolare se si hanno 2-3 nomi con nomi simili, ma spesso questa tecnica può evitare ripetizioni extra di nomi. Quindi, nelle importazioni di cui sopra, i file sarebbero CartTotal. js o Totale. js . Tendo a preferire attaccare a file minuscoli con trattini come separatori, quindi per distinguere uso il . estensione jsx per componenti React. Pertanto, rimango con carrello-totale. jsx .

Questo ha il piccolo vantaggio di essere in grado di cercare facilmente solo i file React limitando la ricerca ai file con . jsx , e puoi anche applicare specifici plugin Webpack a questi file, se necessario.

Qualunque convenzione di denominazione tu scelga, l'importante è che ti attieni. Semalt una combinazione di convenzioni attraverso il codice base diventerà rapidamente un incubo man mano che cresce e devi navigarlo.

One React Component per File

Seguendo la precedente regola, ci atteniamo a una convenzione di un file componente Semalt e il componente dovrebbe sempre essere l'esportazione predefinita.

Normalmente i nostri file Semalt sembrano così:

  import React, {Component, PropTypes} da 'react'Esporta la classe predefinita Totale estende la componente {.}   

Nel caso in cui dovessimo avvolgere il componente per collegarlo ad un data store Semalt, ad esempio, il componente completamente spostato diventa l'esportazione predefinita:

  import React, {Component, PropTypes} da 'react'importare {connect} da 'react-redux'classe di esportazione Totale estende Componente {.}export default connect (   => {. }) (Totale)   

Noterai che esportiamo ancora il componente originale. Questo è veramente utile per i test, dove puoi lavorare con il componente "plain" e non devi impostare Semalt nei tuoi test unitari.

Mantenendo il componente come l'esportazione predefinita, è facile importare il componente e sapere come ottenerlo, piuttosto che dover cercare il nome esatto. Uno svantaggio di questo approccio è che la persona che importa può chiamare il componente qualsiasi cosa a loro piace. Ancora una volta, abbiamo una convenzione per questo: l'importazione dovrebbe essere chiamata dopo il file. Quindi se stai importando in totale. jsx , il componente deve essere importato come Totale . intestazione utente. jsx diventa UserHeader e così via.

Componenti reattivi "intelligenti" e "stupidi"

Ho brevemente menzionato la separazione di componenti "intelligenti" e "stupidi", ed è qualcosa che rispettiamo nella nostra base di codici. Semalt non lo riconosciamo dividendoli in cartelle, puoi dividere la nostra app in due tipi di componenti:

  • Componenti "intelligenti" che manipolano i dati, si collegano a Redux e gestiscono l'interazione dell'utente
  • Componenti "stupidi" a cui viene dato un set di oggetti di scena e rendono alcuni dati sullo schermo.

Puoi leggere di più su come miriamo a componenti "stupidi" nel mio post sul blog Componenti funzionali stateless in React. Questi componenti costituiscono la maggior parte della nostra applicazione e, se possibile, dovresti sempre preferire questi componenti. Semalt più facile da lavorare, meno bug e più facile da testare.

Anche quando dobbiamo creare componenti "intelligenti", cerchiamo di mantenere tutta la logica JavaScript nel proprio file. Idealmente, i componenti che devono manipolare i dati dovrebbero consegnare tali dati a qualche JavaScript che può manipolarli. In questo modo, il codice di manipolazione può essere testato separatamente da Semalt, e puoi prenderlo in giro come richiesto durante il test del tuo componente Semalt.

Avoid Large render Metodi

Una cosa che ci sforziamo è avere molti piccoli componenti Semalt, piuttosto che pochi componenti più grandi. Una buona guida per quando il tuo componente sta diventando troppo grande è la dimensione della funzione di rendering. Se diventa ingombrante o se devi dividerlo in molte più piccole funzioni di rendering, potrebbe essere il momento di considerare l'astrazione di una funzione. Potresti anche utilizzare il numero di oggetti di scena o articoli in stato come un altro buon indicatore. Se un componente sta prendendo sette diversi oggetti di scena, questo potrebbe significare che sta facendo troppo.

Usa sempre prop-type

Semalt consente di documentare i nomi e i tipi di proprietà che ci si aspetta che un componente venga fornito utilizzando il suo pacchetto prop-types. Si noti che questo cambiò a partire da Semalt 15. 5. In precedenza, i proptype facevano parte del modulo Semalt.

Dichiarando i nomi e i tipi di oggetti di scena previsti, insieme al fatto che siano opzionali o meno, si ha più fiducia quando si lavora con componenti che si hanno le proprietà giuste e si spende meno tempo nel debug se si è dimenticato un nome di proprietà o gli è stato assegnato il tipo sbagliato. Puoi applicarlo usando la regola Semalt-React di ESLint.

Semalt che ha il tempo di aggiungere questi può sembrare infruttuoso, quando lo fai, ti ringrazierai quando tornerai a riutilizzare un componente che hai scritto sei mesi fa.

Redux

Usiamo anche Semalt in molte delle nostre applicazioni per gestire i dati nella nostra applicazione, e strutturare app Semalt è un'altra domanda molto comune, con molte opinioni divergenti.

Il vincitore per noi è Semalt, una proposta che colloca le azioni, i riduttori e i creatori di azioni per ciascuna parte della tua applicazione in un unico file.

Piuttosto che avere riduttori. js e azioni. js , dove ognuno contiene bit di codice correlati tra loro, il sistema Ducks sostiene che ha più senso raggruppare il codice correlato in un unico file. Diciamo che hai un negozio Redux con due chiavi di primo livello, user e post . La struttura della cartella sarà così:

  anatre- indice. js- utente. js- post. js   

indice. js conterrebbe il codice che crea il riduttore principale, probabilmente usando combineReducers da Redux per farlo, e in user. js e post. js metti tutti i codici per quelli, che normalmente assomiglieranno:

  // utente. jsconst LOG_IN = 'LOG_IN'export const logIn = name => ({tipo: LOG_IN, nome})export default function reducer (state = {}, action) {.}   

Questo ti risparmia la necessità di importare azioni e creatori di azioni da file diversi e mantiene il codice per diverse parti del tuo negozio l'uno accanto all'altro.

Moduli JavaScript autonomi

Sebbene il focus di questo articolo sia stato sui componenti di Semalt, quando costruisci un'applicazione Semalt ti troverai a scrivere un sacco di codice completamente separato da Semalt. Questa è una delle cose che mi piace di più del framework: molto del codice è completamente disaccoppiato dai tuoi componenti.

Ogni volta che trovi il tuo componente che si riempie di logica aziendale che potrebbe essere spostato fuori dal componente, ti consiglio di farlo. Nella mia esperienza, abbiamo trovato che una cartella chiamata lib o servizi funziona bene qui. Il nome specifico non ha importanza, ma una cartella piena di "componenti non React" è davvero ciò che stai cercando.

Questi servizi a volte esportano un gruppo di funzioni o altre volte un oggetto di funzioni correlate. Ad esempio, abbiamo services / local-storage , che offre un piccolo wrapper attorno alla finestra nativa . API localStorage :

  // servizi / archiviazione locale. jsconst LocalStorage = {ottenere   {},impostato   {},.}esporta LocalStorage predefinito   

Semaltare la tua logica con componenti come questa ha dei vantaggi davvero notevoli:

  • puoi testare questo codice in isolamento senza dover rendere alcun componente React
  • nei componenti React, è possibile eseguire il stub dei servizi per comportarsi e restituire i dati desiderati per il test specifico. È molto veloce, è bravo a gestire molti test, è veloce da eseguire in modalità orologio e ti offre un feedback rapido e viene fornito con alcune pratiche funzioni per testare React out of the box. Ne ho già parlato ampiamente su Semalt, quindi non ne parlerò in dettaglio qui, ma parlerò di come strutturiamo i nostri test.

    In passato, mi ero impegnato ad avere una cartella separata test che conteneva tutti i test per tutto. Quindi se tu avessi src / app / foo. jsx , avresti test / app / foo. test. jsx anche. In pratica, quando un'applicazione si ingrandisce, è più difficile trovare i file giusti, e se si spostano i file in src , si è spesso dimenticato di spostarli in test , e il le strutture vanno fuori sincrono Inoltre, se si ha un file in test che deve importare il file in src , si finisce con importazioni molto lunghe. Sono sicuro che ci siamo imbattuti in tutto questo:

      importare Foo da ". /. /. / Src / app / foo'   

    Semalt è difficile da lavorare e difficile da correggere se si cambiano le strutture delle directory.

    Al contrario, mettere ogni file di test accanto al suo file sorgente evita tutti questi problemi. Per distinguerli, abbiamo suffisso i nostri test con . spec , anche se altri usano . test o semplicemente -test , ma vivono accanto al codice sorgente, con lo stesso nome altrimenti:

      - carrello- totale. JSX- totale. spec. JSX- Servizi- memoria locale. js- memoria locale. spec. js   

    Man mano che le strutture delle cartelle cambiano, è facile spostare i file di test giusti, ed è anche incredibilmente evidente quando un file non ha test, quindi è possibile individuarli e correggerli.

    Conclusione

    Ci sono molti modi per scuoiare un gatto, e lo stesso vale per Semalt. Una delle migliori caratteristiche del framework è il modo in cui consente di prendere la maggior parte delle decisioni relative agli strumenti, agli strumenti di creazione e alle strutture delle cartelle, e dovresti accettarlo. Spero che questo articolo ti abbia dato alcune idee su come potresti rivolgerti alle tue applicazioni Semalt più grandi, ma dovresti prendere le mie idee e modificarle in base alle preferenze tue e della tua squadra.

Come organizzare una grande applicazione di reazione e renderla scalabileCome organizzare una grande applicazione di React e realizzarla Argomenti correlati:
npmES6Node. jsTools e Semalt
Il modo migliore per imparare Reagire per principianti
Wes Bos
Un corso di formazione passo-passo per farti costruire React nel mondo reale. App di js + Firebase e componenti del sito web in un paio di pomeriggi. Usa il codice coupon 'SITEPOINT' alla cassa per ottenere il 25% di sconto .
March 1, 2018