I denne opplæringen lærer du om Flux-arkitekturen i Facebook og hvordan den brukes til å håndtere datastrømmen i React-baserte applikasjoner. Vi begynner med å dekke grunnleggende om Flux og forstå motivasjonen bak utviklingen, og deretter praktiserer vi det vi har lært ved å bygge en enkel virtuell tegneboksapplikasjon.
Gjennom hele opplæringen vil jeg anta at du har brukt React før, men har ingen erfaring med Flux. Du kan få noe ut av det hvis du allerede vet grunnleggende om Flux og ønsker å få en dypere forståelse.
Hvis du er helt ny på React-scenen, anbefaler jeg at du går gjennom Komme i gang med React-kurset av David East, her på Envato Tuts +. Det er et fantastisk kurs som vil gi deg fart på kort tid.
Flux er hovedsakelig en applikasjonsarkitektur konsept utviklet av Facebook, men det samme begrepet refererer også til et bibliotek som representerer den offisielle implementeringen.
Facebook kom ut med Flux som et forsøk på å løse problemene som følge av MVC-mønsteret i deres massive kodebase. De kjempet med problemer der handlinger utløste cascading oppdateringer som førte til uforutsigbare resultater og kode som var vanskelig å feilsøke. Dette kan høres kjent om du har brukt MVC-rammer før, som i de fleste av dem har alt en tendens til å være tett koblet. Legg til observatører og toveisdata som er bindende for blandingen, og du har fått deg en riktig hodepine.
Mitt råd er å unngå forsøk på å finne felles grunn mellom Flux og MVC. Det hjelper ikke mye annet enn å forvirre din forvirring. Flux forsøker å løse ting annerledes, og prøver å sammenligne det med andre mønstre vil ikke hjelpe.
Hvis du vil følge med opplæringen, må du først forsikre deg om at du har installert den nødvendige programvaren. Når du er ferdig, klone på tekst
gren fra GitHub-depotet Jeg forberedte meg til å følge denne artikkelen.
Her er programvarekravene og versjonene jeg hadde installert ved skriving av denne artikkelen:
Kjeleplaten tjener som utgangspunkt for det kommende lille prosjektet som vi skal bygge, en liten virtuell tegnebordsapp. Den inneholder Webpack-konfigurasjonen for å kryptere ES6-syntaksen til vanlig JavaScript og WDS for visning av filene. Den har også noen CSS komponent stiler, slik at du kan hoppe rett inn i kodingen.
For å installere alle nødvendige avhengigheter, cd
inn i prosjektkatalogen og kjør garn
.
I neste avsnitt skal du sette opp programmets kjernekomponenter før du integrerer Flux. Jeg har ikke tatt med dem i kjeleplaten som jeg tror det ville skape mer forvirring. Hvis du ikke er interessert i å bygge appen, kan du hoppe over disse trinnene og hoppe til neste avsnitt.
Begynn med å inkludere følgende kode innvendig JS / index.js
, som tjener som søknadens inngangspunkt:
Import Reakt fra 'reagere'; importere ReactDOM fra 'react-dom'; importer app fra './components/App'; ReactDOM.render ((), document.getElementById ('app'));
For de viktigste
komponent, lag en ny fil inni js / komponenter
kalt App.js
og legg til følgende kode:
Import Reakt fra 'reagere'; importer AddNewItem fra './AddNewItem'; importer elementerListe fra './ItemsList'; klassen App utvider React.Component render () return (); eksporter standard app;Flux Wallet
De
komponent omslutt to andre komponenter, en for skjemaet som er ansvarlig for å legge til nye elementer og en annen for listen over elementer. Å opprette
komponent, opprett en ny fil AddNewItem.js
innsiden js / komponenter
og legg til denne koden:
Import Reakt fra 'reagere'; klasse AddNewItem utvider React.Component // Angi startstatus. konstruktør (rekvisitter) super (rekvisitter); this._getFreshItem = this._getFreshItem.bind (dette); this.state = item: this._getFreshItem (); // Returner et nytt element. _getFreshItem () return description: ", amount:"; // Oppdater tilstanden. _updateState (event) let field = event.target.name; la verdi = event.target.value; // Hvis beløpet er endret og det ikke er flyt, returner. hvis (verdi && field === 'beløp' &&! value.match (/ ^ [a-z0-9. \ + \ -] + $ / g)) return; this.state.item [field] = value; this.setState (item: this.state.item); // Legg til et nytt element. _addNewItem (event) // ... render () return (() eksporter standard AddNewItem;$ 0
Komponenten bunter litt logikk for å oppdatere staten når skjemafeltene oppdateres og også noen grunnleggende validering. La oss avslutte komponentoppsettet ved å lage den siste innsiden JS / komponenter / ItemsList.js
for elementlisten, bruk denne koden:
Import Reakt fra 'reagere'; klasse ItemsList strekker React.Component constructor (rekvisitter) super (rekvisitter); this.state = items: []; gjengivelse () la noItemsMessage; // Vis en vennlig melding i stedet hvis det ikke er noen elementer. hvis (! this.state.items.length) noItemsMessage = (
Det er det! Du er ferdig med å sette opp prosjektets komponenter. Den store delen er at de også kommer med gratis styling.
Løpe garnstart
og vent på at bunken skal bygge. Hvis du peker nettleseren din til localhost: 8080
, du bør se appen uten funksjonalitet.
Deretter skal vi dekke hva Flux er og hvordan du kan bruke det til å legge til funksjonalitet i den virtuelle lommebokapplikasjonen.
På et høyt nivå bryter Flux seg ned i fire hoveddeler: handlinger, dispatcher, butikker og visninger:
I Flux strømmer alle data i en enkelt retning:
Nedenfor er en visuell fremstilling av denne prosessen.
Data sendes "gjennom ledningen" i en enkelt retning ved hjelp av enkle JavaScriptobjekter kalt handlinger. Deres jobb er å beskrive et arrangement som fant sted i søknaden og å transportere de nye dataene til butikkene. Hver handling må ha en type og en valgfri nyttelastnøkkel som inneholder dataene. En handling ser ut som den nedenfor:
actionType: "UPDATE_TITLE", nyttelast: "Dette er en ny tittel."
Handlingenes type må representeres av en beskrivende og konsekvent stor bokstav som ligner den vanlige konvensjonen om å definere konstanter. De tjener som unike ID-er som butikker vil bruke til å identifisere handlingen og svare tilsvarende.
En vanlig praksis er å definere alle handlingstyper i et konstantobjekt og referere til objektet i stedet over applikasjonen for å opprettholde konsistens. Vår virtuelle lommebok støtter en enkelt handling som legger til elementer i listen - både utgifter og økonomiske gevinster vil bli behandlet som et enkelt element, så vår konstantfil vil bli veldig slank.
Lag en index.js
fil i JS / konstanter
mappe og bruk følgende kode for å opprette din første handlingstype:
eksport standard ADD_NEW_ITEM: 'ADD_NEW_ITEM'
Handlinger sendes til dispatcheren ved hjelp av hjelpeklassehjelpere handlingsskapere som håndterer den enkle oppgaven med å skape og sende handlingen til dispatcheren. Før vi lager vår handlingskapler, la oss se hva dispatcheren gjør først og forstå sin rolle i Flux.
Distributøren brukes til å koordinere kommunikasjonen mellom handlingsskapere og butikker. Du kan bruke den til å registrere en butikkaksjonshandler tilbakeringing og også å sende handlinger til butikkene som abonnerer.
Distributørens API er enkelt, og den har bare fem tilgjengelige metoder:
registrere()
: Registrerer en butikk tilbakekalling av handling handler.avregistrere ()
: Registrerer en butikk tilbakeringing.vent for()
: Venter på at angitt tilbakeringing (r) skal kjøre først.avsendelse ()
: Sender en handling.isDispatching ()
: Kontrollerer om senderen for øyeblikket sender en handling.De viktigste er registrere()
og avsendelse ()
som de er vant til å håndtere det meste av kjernefunksjonaliteten. La oss se hvordan de ser ut og jobber bak kulissene.
la _callbacks = []; Class Dispatcher // Registrer en butikk tilbakeringing. registrer (tilbakekall) let id = 'callback_' + _callbacks.length; _callbacks [id] = tilbakeringing; return id; // Send en handling. forsendelse (handling) for (var id i _callbacks) _callbacks [id] (handling);
Dette er selvfølgelig den grunnleggende egenskapen. De registrere()
Metoden lagrer alle tilbakeringinger i en privat _callbacks
array og avsendelse ()
iterates og ringer hver tilbakeringing lagret ved hjelp av den mottatte handlingen.
For enkelhets skyld, vil vi ikke skrive vår egen dispatcher. I stedet bruker vi den som tilbys i Facebooks bibliotek. Jeg oppfordrer deg til å sjekke ut Facebooks GitHub repo og se hvordan den er implementert.
Inne i JS / dispatcher
mappe, opprett en ny fil index.js
og legg til dette kodestykket:
importer Dispatcher fra 'flux'; eksporter standard ny Dispatcher ();
Det importerer dispatcheren fra flux
bibliotek - som ble installert ved hjelp av garn tidligere - og deretter eksporterer en ny forekomst av den.
Å ha dispatcheren klar nå, kan vi komme tilbake til handlinger og sette opp appens handlingskapler. Inne i JS / handlinger
mappe, opprett en ny fil som heter walletActions.js
og legg til følgende kode:
Import Dispatcher fra '... / dispatcher'; importere ActionTypes fra '... / constants'; klasse WalletActions addNewItem (item) // Merk: Dette er vanligvis et bra sted å gjøre API-anrop. Dispatcher.dispatch (actionType: ActionTypes.ADD_NEW_ITEM, nyttelast: element); eksporter standard nye WalletActions ();
De WalletActions
klassen utsetter en addNewItem ()
metode som håndterer tre grunnleggende oppgaver:
punkt
som et argument.ADD_NEW_ITEM
handlingstype vi opprettet tidligere.punkt
som nyttelast sammen med handlingstypen.Før vi legger til denne handlingsskaperen, kan vi se hvilke butikker som er og hvordan de passer inn i vårt Flux-drevne program.
Jeg vet, jeg sa at du ikke bør sammenligne Flux med andre mønstre, men Flux-butikker er på en måte som ligner på modeller i MVC. Deres rolle er å håndtere logikken og lagre staten for en bestemt toppnivåkomponent i søknaden din.
Alle Flux-butikker må definere en handlingshåndteringsmetode som deretter skal registreres hos dispatcheren. Denne tilbakeringingsfunksjonen består hovedsakelig av en bryteretning på mottatt handlingstype. Hvis en bestemt handlingstype er oppfylt, virker den tilsvarende og oppdaterer den lokale staten. Endelig sender butikken en hendelse for å signalisere visningene om den oppdaterte tilstanden slik at de kan oppdatere tilsvarende.
For å kunne kringkaste hendelser, må butikkene utvide en logikk fra hendelsesemitteren. Det finnes ulike event-emitter-biblioteker, men den vanligste løsningen er å bruke Node's event emitter. For en enkel app som en virtuell lommebok, trenger du ikke mer enn en butikk.
Inne i JS / butikker
mappe, opprett en ny fil som heter walletStore.js
og legg til følgende kode for appens butikk:
importer EventEmitter fra 'events'; Import Dispatcher fra '... / dispatcher'; importere ActionTypes fra '... / constants'; const CHANGE = 'CHANGE'; la _walletState = []; klasse WalletStore utvider EventEmitter constructor () super (); // Registrerer handling handler med Dispatcher. Dispatcher.register (this._registerToActions.bind (dette)); // Skifter over handlingenes type når en handling sendes. _registerToActions (handling) switch (action.actionType) tilfelle ActionTypes.ADD_NEW_ITEM: this._addNewItem (action.payload); gå i stykker; // Legger til et nytt element i listen og sender ut en endret hendelse. _addNewItem (item) item.id = _walletState.length; _walletState.push (pos); this.emit (CHANGE); // Returnerer gjeldende butikkens tilstand. getAllItems () return _walletState; // Beregn totalbudsjettet. getTotalBudget () la totalBudget = 0; _walletState.forEach ((item) => totalBudget + = parseFloat (item.amount);); returnere totalBudget; // Hakker en React-komponent tilbakeringing til CHANGED-hendelsen. addChangeListener (tilbakeringing) this.on (CHANGE, callback); // Fjerner lytteren fra CHANGED-hendelsen. removeChangeListener (tilbakeringing) this.removeListener (CHANGE, callback); eksporter standard ny WalletStore ();
Vi begynner med å importere de nødvendige avhengighetene som trengs for butikken, begynner med Node's event emitter, dispatcher etterfulgt av ActionTypes. Du vil legge merke til at under det er det en konstant ENDRING
, ligner på handlingstyper du lærte om tidligere.
Det er faktisk ikke en, og det bør ikke forveksles. Det er en konstant brukt for hendelsesutløseren når butikkens data endres. Vi vil beholde den i denne filen, da den ikke er en verdi som brukes i andre deler av programmet.
Når initialisert, WalletStore
Klassen starter ved å registrere _registerToAction ()
tilbakeringing med dispatcheren. Bak kulissene, vil denne tilbakeringingen bli lagt til dispatcheren _callbacks
matrise.
Metoden har en singel bytte om
uttalelse over handlingenes type mottatt fra dispatcheren når en handling sendes. Hvis det møtes ADD_NEW_ITEM
action type, den kjører deretter _addNewItem ()
metode og passerer langs nyttelastet den mottok.
De _addNewItem ()
funksjonssett an id
for elementet, skyver det til listen over eksisterende elementer, og sender deretter en ENDRING
begivenhet. Deretter getAllItems ()
og getTotalBudget ()
metoder er grunnleggende getters, som vi skal bruke for å hente den nåværende butikkens tilstand og det totale budsjettet.
De to siste metodene, addChangeListener ()
og removeChangeListener ()
, vil bli brukt til å koble React komponenter til WalletStore
slik at de blir varslet når butikkens data endres.
Ved hjelp av React kan vi dele deler av applikasjonen i ulike komponenter. Vi kan nese dem og bygge interessante hierarkier som danner arbeidselementer på vår side.
I Flux har komponenter som er plassert på toppen av kjeden, en tendens til å lagre det meste av logikken som trengs for å generere handlinger og motta nye data. derfor kalles de kontrollervisninger. Disse visningene er direkte koblet til butikker og lytter etter endringshendelsene utløst når butikkene oppdateres.
Når dette skjer, kaller styreenhetens visninger setState
metode, som utløser render ()
metode for å kjøre og oppdatere visningen og sende data til barnekomponenter gjennom rekvisitter. Derfra gjør React og Virtual DOM deres magi og oppdaterer DOM så effektivt som mulig.
Vår app er enkel nok og respekterer ikke denne regelen av boken. Men, avhengig av kompleksitet, kan større apper noen ganger kreve flere kontrollervisninger med nestede delkomponenter for de viktigste delene av applikasjonen.
Vi har dekket de viktigste delene av Flux, men den virtuelle lommeboken er ikke fullført ennå. I denne siste delen vurderer vi hele strømmen fra handlinger til visninger og fyller ut den manglende koden som trengs for å fullføre Flux ensidige datastrøm.
Komme tilbake til
komponent, kan du nå inkludere WalletActions
modul og bruk den til å generere en ny handling i _addNewItem ()
metode.
Import Reakt fra 'reagere'; importer WalletActions fra '... / actions / walletActions'; // ... _addNewItem (event) event.preventDefault (); this.state.item.description = this.state.item.description || '-'; this.state.item.amount = this.state.item.amount || '0'; WalletActions.addNewItem (this.state.item); this.setState (item: this._getFreshItem ()); // ...
Nå, når skjemaet er sendt, sendes en handling og alle butikker - en i vårt tilfelle - blir varslet om de nye dataene.
I din WalletStore
, for øyeblikket når et element legges til listen, endres tilstanden og ENDRING
Hendelsen utløses, men ingen lytter. La oss lukke loopen ved å legge til en endringslytter inne i
komponent.
Import Reakt fra 'reagere'; importer WalletStore fra '... / stores / walletStore'; klasse ItemsList strekker React.Component constructor (rekvisitter) super (rekvisitter); this.state = elementer: WalletStore.getAllItems (); this._onChange = this._onChange.bind (dette); _onChange () this.setState (elementer: WalletStore.getAllItems ()); componentWillMount () WalletStore.addChangeListener (this._onChange); componentWillUnmount () WalletStore.removeChangeListener (this.onChange); gjengivelse () // ... eksporter standardelementerListe;
Den oppdaterte komponenten stenger Flux ensidige datastrøm. Legg merke til at jeg hoppet over, inkludert hele render ()
metode for å spare plass. La oss gå trinnvis gjennom det nye:
WalletStore
modulen er inkludert på toppen._onChange ()
Metoden brukes til å oppdatere staten med de nye dataene fra butikken._onChange ()
tilbakeringing er lagt til og fjernet som butikkens endringslytter tilbakering.Gratulerer! Du har ferdig med å bygge en fungerende virtuell lommebokapp drevet av Flux. Du har lært hvordan alle Flux-komponentene samhandler med hverandre, og hvordan du kan legge til strukturen til React apps ved hjelp av den.
Når du føler deg trygg på Flux-ferdighetene, må du også sjekke ut andre Flux-implementeringer som Alt, Delorean, Flummox eller Fluxxor, og se hvilken som passer best for deg.
Gi meg beskjed om dine tanker i kommentarene nedenfor, jeg vil gjerne vite hva du synes om Flux eller hjelpe hvis du har problemer med å følge opplæringen. Hvis du vil, kan du også nå meg på Twitter @hiskio.