Intro til React Framework

I dagens verden av Javascript Application rammer, er designfilosofien den viktigste differensieringsfaktoren. Hvis du sammenligner de populære JS-rammene, som EmberJS, AngularJS, Backbone, Knockout, etc., er du sikker på å finne forskjeller i deres abstraksjoner, tankemodeller og selvfølgelig terminologien. Dette er en direkte konsekvens av den underliggende designfilosofien. Men i prinsippet gjør de alle en ting, som er å abstrahere DOM på en slik måte at du ikke håndterer direkte med HTML-elementer.

Jeg tror personlig at et rammeverk blir interessant når det gir et sett av abstraksjoner som muliggjør en annen tenkemåte. I dette aspektet, reagerer, vil det nye JS-rammeverket fra folkene på Facebook, tvinge deg til å tenke på (i noen grad) hvordan du dekomponerer brukergrensesnittet og samspillet mellom søknaden din. Etter å ha nådd versjon 0.4.1 (som av denne skrivingen) gir React en overraskende enkel, men likevel effektiv modell for å bygge JS apps som blander en herlig cocktail av en annen type.

I denne artikkelen vil vi utforske byggeklossene i React og omfavne en stil av tenkning som kan virke motstridende på første gang. Men som React docs sier: "Gi det fem minutter" og så vil du se hvordan denne tilnærmingen blir mer naturlig.

motivasjon

Historien om React startet innen Facebook, hvor den brygget for en stund. Etter å ha nådd en stabilt nok stat, bestemte utviklerne seg for å åpne den for noen måneder tilbake. Interessant er Instagram-nettsiden også drevet av React Framework.

React nærmer seg DOM-abstraksjonsproblemet med en litt annen oppgave. For å forstå hvordan dette er annerledes, lar vi raskt glosse over teknikkene vedtatt av rammene jeg nevnte tidligere.

En høyt nivå oversikt over JS Application Framework

MVC-modellen (Model-View-Controller) er fundamentalt for UI-utvikling, ikke bare i webapplikasjoner, men i front-end-applikasjoner på alle plattformer. I tilfelle av webapps er DOM den fysiske representasjonen av en visning. DOM-en er generert fra en tekstlig HTML-mal som trekkes fra en annen fil, en script-blokk eller en forhåndskompilert malfunksjon. De Utsikt er en enhet som bringer tekstmalen til liv som et DOM-fragment. Det setter også opp hendelseshåndterer og tar seg av å manipulere DOM-treet som en del av sin livssyklus.

For Utsikt For å være nyttig, trenger den å vise noen data, og muligens tillate brukerinteraksjon. Dataene er Modell, som kommer fra en datakilde (en database, web-tjeneste, lokal lagring, etc.). Rammer gir en måte å "binde" dataene til visningen, slik at endringer i data reflekteres automatisk med endringer i visningen. Denne automatiske prosessen kalles data-bindende og det er APIer / teknikker for å gjøre dette så sømløst som mulig.

MVC triaden er fullført av Controller, som engasjerer Utsikt og Modell og orkestrerer dataflyten (Modell) inn i det Utsikt og bruker-hendelser ut fra Utsikt, muligens fører til endringer i Modell.


Rammer som automatisk håndterer datastrømmen frem og tilbake mellom Vis og modell, opprettholder en intern event-loop. Denne hendelsesløkken er nødvendig for å lytte til bestemte brukerhendelser, dataendringshendelser, eksterne utløsere, osv., Og deretter avgjøre om det er noen endring fra forrige løp i løkken. Hvis det er endringer, i hver ende (Vis eller Modell), sikrer rammen at begge blir brakt tilbake i synkronisering.

Hva som gjør Reag forskjellig?

Med React tar Vis-delen av MVC-triaden en fremtredende rolle og rulles inn i en enhet kalt Komponent. Komponenten opprettholder en ubrukt eiendomspose som kalles Rekvisitter, og a stat som representerer brukerens drevne tilstand av brukergrensesnittet. Visningsgenereringsdelen av Komponent er ganske interessant og muligens årsaken til at React skiller seg ut i forhold til andre rammer. I stedet for å bygge en fysisk DOM direkte fra en malfil / script / funksjon, vil Komponent genererer et mellomliggende DOM som er en stand-in for den virkelige HTML DOM. Et ekstra trinn blir da tatt for å oversette denne mellomliggende DOM til den virkelige HTML DOM.

Som en del av den mellomliggende DOM generasjonen, er Komponent Henger også hendelsesbehandlere og binder dataene i Rekvisitter og stat.

Hvis ideen om en mellomliggende DOM høres litt fremmed, må du ikke være for alarmert. Du har allerede sett denne strategien vedtatt av språkkjøretider (aka virtuelle maskiner) for tolkede språk. Vår egen JavaScript runtime, genererer først en mellomliggende representasjon før du spytter ut den opprinnelige koden. Dette gjelder også for andre VM-baserte språk som Java, C #, Ruby, Python, osv.

React vedtar smart denne strategien for å lage en mellomliggende DOM før du genererer den endelige HTML DOM. Mellom-DOM er bare en JavaScript-objektgraf og blir ikke gjengitt direkte. Det er et oversettelsestrinn som skaper den virkelige DOM. Dette er den underliggende teknikken som gjør React gjøre DOM-manipulasjoner raskt.

Reagere i dybden

For å få et bedre bilde av hvordan React gjør det hele, la oss dykke litt dypere; starter med Komponent. Komponenten er den primære byggeblokken i React. Du kan komponere brukergrensesnittet til søknaden din ved å sette sammen et tre av komponenter. Hver komponent gir en implementering for render () metode, der den lager mellomliggende DOM. ringe React.renderComponent () på roten Komponent resulterer i rekursivt å gå ned i komponent-treet og bygge opp mellom-DOM. Mellom-DOM konverteres da til den ekte HTML DOM.


Siden mellomliggende DOM-opprettelsen er en integrert del av komponenten, gir React en praktisk XML-basert utvidelse til JavaScript, kalt JSX, for å bygge komponent-treet som et sett med XML-noder. Dette gjør det enklere å visualisere og begrunnes om DOM. JSX forenkler også foreningen av hendelsesbehandlere og egenskaper som xml-attributter. Siden JSX er et utvidelsesspråk, er det et verktøy (kommandolinje og i nettleser) for å generere den endelige JavaScript. En JSX XML-kode kaster direkte til en komponent. Det er verdt å påpeke at React fungerer uavhengig av JSX og JSX-språket gjør det enkelt å lage mellomliggende DOM.

tooling

Kjerne React Framework kan lastes ned fra deres hjemmeside. I tillegg til JSX → JS-transformasjonen kan du enten bruke JSXTransformer i nettleseren eller bruke kommandolinjeverktøyet, kalt reagensverktøy (installert via NPM). Du trenger en installasjon av Node.js for å laste den ned. Kommandolinjeverktøyet lar deg forkompilere JSX-filene og unngå oversettelsen i nettleseren. Dette anbefales definitivt hvis JSX-filene dine er store eller mange i nummer.

En enkel komponent

OK, vi har sett mye teori så langt, og jeg er sikker på at du er kløe for å se noen ekte kode. La oss dykke inn i vårt første eksempel:

/ ** @jsx React.DOM * / var Simple = React.createClass (getInitialState: function () return count: 0;, handleMouseDown: function () alert ('Jeg ble fortalt:' + dette. props.message); this.setState (count: this.state.count + 1);, gjengi: funksjon () retur 
Gi meg beskjeden!
Melding overført This.state.count tid (s)
; ); React.renderComponent (, document.body);

Selv om det er enkle, dekker koden ovenfor en god mengde React overflaten:

  • Vi lager den enkle komponenten ved å bruke React.createClass og passerer inn i en gjenstand som utfører noen kjernefunksjoner. Den viktigste er den render (), som genererer mellomliggende DOM.
  • Her bruker vi JSX til å definere DOM og også vedlegg Mousedown Event-Handler. De syntaks er nyttig for å inkorporere JavaScript-uttrykk for attributter (onMouseDown = this.handleClick) og barneknuter ( This.state.count). Hendelseshandlere som er assosiert med -syntaxen, bindes automatisk til forekomsten av komponenten. Og dermed dette inne i hendelseshåndteringsfunksjonen refererer til komponenteksemplet. Kommentaren på første linje / ** @jsx React.DOM * / er en kø for JSX-transformatoren for å gjøre oversettelsen til JS. Uten denne kommentarlinjen, vil ingen oversettelse finne sted.

Vi kan kjøre kommandolinjeværktøyet (jsx) i watch-modus og automatisk kompilere endringer fra JSX → JS. Kildefilene er inne / src mappe og utgangen genereres i /bygge.

jsx - watch src / build /

Her er den genererte JS-filen:

/ ** @jsx React.DOM * / var Simple = React.createClass (displayName: 'Simple', getInitialState: funksjon () return count: 0;, handleMouseDown: function () alert fortalte: '+ this.props.message); this.setState (count: this.state.count + 1);, gjengi: funksjon () return React.DOM.div (null, React.DOM.div (className: "clicker", onMouseDown: this.handleMouseDown, "Gi meg meldingen!"), React.DOM.div (className: "message", "Message conveyed", React.DOM.span className: "count", this.state.count), "time (s)"));); React.renderComponent (Simple (message: "Keep it Simple"), document.body);

Legg merke til hvordan

og tagger kart til forekomster av React.DOM.div og React.DOM.span.

  • La oss nå komme tilbake til vårt kodeeksempel. Innsiden handleMouseDown, vi benytter oss av this.props å lese budskap eiendom som ble sendt inn. Vi satte budskap på siste linje i koden, i anropet til React.renderComponent () hvor vi lager komponent. Meningen med this.props er å lagre dataene som ble sendt inn i komponenten. Det regnes som uendelig, og bare en komponent på høyere nivå får lov til å gjøre endringer og sende det ned til komponenttreet.
  • Innsiden handleMouseDown Vi stiller også noen brukerstatus med this.setState () for å spore hvor mange ganger meldingen ble vist. Du vil legge merke til at vi bruker this.state i render () metode. Når som helst du ringer setState (), Reakt utløser også render () metode for å holde DOM synkronisert. I tillegg React.renderComponent (), setState () er en annen måte å tvinge en visuell oppdatering på.

Syntetiske hendelser

Hendelsene som er eksponert på mellomliggende DOM, for eksempel onMouseDown, fungere også som et lag av indirection før de blir satt på real-DOM. Disse hendelsene er derfor referert til som Syntetiske hendelser. React vedtar hendelsesdelegasjon, som er en velkjent teknikk, og vedlegger hendelser bare på rotnivået til real-DOM. Dermed er det bare en sann event-handler på real-DOM. I tillegg gir disse syntetiske hendelsene også et konsistensnivå ved å skjule nettleser- og elementforskjeller.

Kombinasjonen av mellomliggende DOM og syntetiske hendelser gir deg en standard og konsistent måte å definere brukergrensesnitt på forskjellige nettlesere og til og med enheter.

Komponentets livssyklus

Komponenter i React-rammeverket har en spesifikk livssyklus og legemliggjør en statsmaskin som har tre forskjellige tilstander.


Komponenten kommer til liv etter å ha vært montert. Montering resulterer i å gå gjennom et gjengivelsespass som genererer komponent-treet (mellomliggende DOM). Dette treet er konvertert og plassert i en container-node av den virkelige DOM. Dette er et direkte utfall av anropet til React.renderComponent ().

Når den er montert, forblir komponenten i Oppdater stat. En komponent blir oppdatert når du endrer tilstand ved hjelp av setState () eller endre rekvisitter med setProps (). Dette resulterer igjen i å ringe render (), som bringer DOM synkronisert med dataene (Rekvisitter + stat). Mellom påfølgende oppdateringer beregner React deltaet mellom det forrige komponenttreet og det nylig genererte treet. Dette er et svært optimalisert trinn (og et flaggskip-funksjon) som minimerer manipulasjonen på den virkelige DOM.

Den endelige staten er umontert. Dette skjer når du kaller eksplisitt React.unmountAndReleaseReactRootNode () eller automatisk hvis en komponent var et barn som ikke lenger var generert i en render () anrop. Oftest trenger du ikke å håndtere dette og bare la React gjøre det riktige.

Nå ville det vært et stort referanse, hvis React ikke fortalte deg når det flyttet mellom Montert-Update-Umontert stater. Heldigvis er det ikke tilfelle, og det er kroker du kan overstyre for å bli varslet om endringer i livssyklusen. Navnene snakker for seg selv:

  • getInitialState (): Forbered opprinnelig tilstand for komponenten
  • componentWillMount ()
  • componentDidMount ()
  • componentWillReceiveProps ()
  • shouldComponentUpdate (): nyttig hvis du vil kontrollere når en gjengivelse skal hoppes over.
  • componentWillUpdate ()
  • render ()
  • componentDidUpdate ()
  • componentWillUnmount ()

De componentWill * metoder kalles før staten endres og componentDid * metoder kalles etter.

Noen av metodenavnene ser ut til å ha tatt et tegn fra kakaoverkene i Mac og iOS

Diverse funksjoner

Innenfor et komponent-tre skal data alltid strømme ned. En overordnet komponent skal angi Rekvisitter av en barnekomponent for å overføre data fra foreldrene til barnet. Dette kalles som Eier-Owned par. På den annen side vil brukerhendelser (mus, tastatur, berøringer) alltid boble opp fra barnet helt til rotkomponenten, med mindre det håndteres mellom.


Når du oppretter mellomliggende DOM i render (), du kan også tilordne en ref eiendom til en barnekomponent. Du kan da referere til det fra foreldrene ved hjelp av refs eiendom. Dette er avbildet i utsnittet nedenfor.

 gjengivelse: funksjon () // Sett en ref retur 
This.state.count
; handleMouseDown: funksjon () // Bruk ref console.log (this.refs.counter.innerHTML); ,

Som en del av komponentmetadataene kan du angi starttilstanden (getInitialState ()), som vi så tidligere innen livscyklusmetodene. Du kan også angi standardverdiene til rekvisita med getDefaultProps () og også etablere noen valideringsregler på disse rekvisitaene ved hjelp av propTypes. Dokumentene gir en fin oversikt over de ulike typer valideringer (type sjekker, påkrevd, etc.) du kan utføre.

React støtter også konseptet a mixin å trekke ut gjenbrukbare stykker av atferd som kan injiseres i forskjellige komponenter. Du kan passere mixins ved hjelp av mixins egenskap av en komponent.

Nå kan vi bli virkelige og bygge en mer omfattende komponent som bruker disse funksjonene.

En Shape Editor bygget ved hjelp av React

I dette eksemplet vil vi bygge en redaktør som aksepterer et enkelt DSL (Domain Specific Language) for å lage former. Når du skriver inn, ser du tilsvarende utdata på siden, og gir deg tilbakemelding på nettet.

DSL lar deg lage tre typer former: Ellipse, rektangel og tekst. Hver form er spesifisert på en egen linje sammen med en haug med stylingsegenskaper. Syntaxen er grei og låner litt fra CSS. For å analysere en linje, bruker vi en Regex som ser ut som:

 var formRegex = / (rect | ellipse | tekst) (\ s [a-z] +: \ s [a-z0-9] +;) * / i;

Som et eksempel beskriver følgende sett med linjer to rektangler og en tekstetikett ...

// Reag etiketttekst verdi: React; farge: # 00D8FF; skriftstørrelse: 48px; tekstskygge: 1px 1px 3px # 555; polstring: 10px; venstre: 100px; topp: 100px; // venstre logo rekt bakgrunn: url (react.png) no-repeat; grense: ingen; bredde: 38; høyde: 38; venstre: 60px; topp: 120px; // høyre logo rett bakgrunn: url (react.png) no-repeat; grense: ingen; bredde: 38; høyde: 38; venstre: 250px; topp: 120px;

... genererer produksjonen vist nedenfor:


Setter opp

OK, la oss fortsette å bygge denne redaktøren. Vi starter med HTML-filen (index.html), der vi legger inn toppnivåoppslaget og inkluderer bibliotekene og programskriptene. Jeg viser bare de relevante delene her:

  

I den ovennevnte koden, er container div har vår React generated DOM. Våre søknadsskript er inkludert fra /bygge katalogen. Vi bruker JSX i våre komponenter og kommandolinjevaktaren (jsx), setter de konverterte JS-filene inn i /bygge. Merk at denne overvåkerkommandoen er en del av reagere-verktøy NPM-modul.

jsx - watch src / build /

Redaktøren er delt inn i et sett med komponenter, som er oppført nedenfor:

  • ShapeEditor: Roten Komponent i komponent-treet
  • ShapeCanvas: ansvarlig for å generere formen-komponentene (ellipse, rektangel, tekst). Den finnes i ShapeEditor.
  • ShapeParser: ansvarlig for å tolke tekst og utvinne listen over formdefinisjoner. Det analyserer linje for linje med Regex vi så tidligere. Ugyldige linjer ignoreres. Dette er egentlig ikke en komponent, men et helper JS-objekt, som brukes av ShapeEditor.
  • Ellipse, rektangel, tekst: Formen Komponenter. Disse blir barn til ShapeCanvas.
  • ShapePropertyMixin: Gir hjelpefunksjoner for utvinning av stiler som finnes i formdefinisjonene. Dette er blandet inn i de tre formene-komponentene ved hjelp av mixins eiendom.
  • app: inngangspunktet for redaktøren. Den genererer rotkomponenten (ShapeEditor), og lar deg velge en formeksempel fra rullegardinmenyen.

Forholdet mellom disse enhetene vises i det annoterte komponent-treet:


The ShapeEditor Component

Leter på implementeringen av noen av disse komponentene, begynner med ShapeEditor.

/ ** @jsx React.DOM * / var ShapeEditor = React.createClass (componentWillMount: funksjon () this._parser = ny ShapeParser ();, getInitialState: funksjon () return text: ";, gjengi: funksjon () var former = this._parser.parse (this.state.text); var tree = (