Introduktion till React Framework

I dagens värld av Javascript Application Framework är designfilosofin den viktigaste differentieringsfaktorn. Om du jämför de populära JS-ramarna, som EmberJS, AngularJS, Backbone, Knockout, etc., är du säker på att hitta skillnader i deras abstraktioner, tänkande modeller och naturligtvis terminologin. Detta är en direkt följd av den underliggande designfilosofin. Men i princip gör de alla en sak, som är att abstrahera DOM på ett sådant sätt att du inte hanterar HTML-element direkt.

Jag tycker personligen att en ram blir intressant när den ger en uppsättning abstraktioner som möjliggör ett annat sätt att tänka. I den här aspekten, reagera, den nya JS-ramen från folk på Facebook, kommer att tvinga dig att ompröva (i viss utsträckning) hur du sönderdelar användargränssnittet och interaktionerna i din ansökan. Efter att ha nått version 0.4.1 (enligt detta skrivande) ger React en överraskande enkel men ändå effektiv modell för att bygga JS-appar som blandar en härlig cocktail av olika slag.

I den här artikeln kommer vi att utforska byggblocken i React och omfamna en stil av tänkande som kan verka kontraintetiv vid första försöket. Men, som React docs säger: "Ge det fem minuter" och då kommer du att se hur denna tillvägagångssätt blir mer naturlig.

motiveringar

Berättelsen om React började inom gränserna för Facebook, där den bryggdes en stund. Efter att ha nått ett stabilt nog tillstånd bestämde sig utvecklarna att öppna källan det några månader tillbaka. Intressant är Instagram-webbplatsen även drivs av React Framework.

React närmar sig DOM-abstraktionsproblemet med en något annorlunda take. För att förstå hur det här är annorlunda kan vi snabbt glansa över de tekniker som antagits av de ramar jag nämnde tidigare.

En högnivåöversikt av JS Application Framework

MVC-modellen (Model-View-Controller) är grundläggande för UI-utveckling, inte bara i webapps, men i front-end-applikationer på vilken plattform som helst. Vid webbapps är DOM den fysiska representationen av en vy. DOM själv genereras från en texthtml-mall som dras från en annan fil, en script-block eller en förkompilerad mallfunktion. De Se är en enhet som bringar textmallen till liv som ett DOM-fragment. Det skapar också händelsehanterare och tar hand om att manipulera DOM-trädet som ett led i sin livscykel.

För Se För att vara användbar måste den visa vissa data och möjliggöra användarinteraktion. Uppgifterna är Modell, som kommer från en viss datakälla (en databas, webbtjänst, lokal lagring etc.). Ramar ger ett sätt att "binda" data till vyn, så att ändringar i data återspeglas automatiskt med ändringar i vyn. Denna automatiska process kallas uppgifter bindande och det finns API / tekniker för att göra detta så smidigt som möjligt.

MVC triaden är klar av Kontrollant, som engagerar Se och den Modell och orkestrerar flödet av data (Modell) in i Se och användarhändelser ut från Se, möjligen leda till förändringar i Modell.


Ramar som automatiskt hanterar flödet av data fram och tillbaka mellan View och Model behåller en intern händelsesslinga. Denna händelsesslinga behövs för att lyssna på vissa användarhändelser, dataändringshändelser, externa utlösare, etc. och sedan avgöra om det finns någon förändring från den tidigare körningen av slingan. Om det finns ändringar, i båda ändar (Visa eller Modell), säkerställer ramverket att båda tas tillbaka i synkronisering.

Vad som gör reaktion annorlunda?

Med React tar View-delen av MVC-triaden en framträdande roll och rullas in i en enhet som heter Komponent. Komponenten upprätthåller en immateriell egenskapspåse som heter rekvisita, och a stat som representerar användar-driven tillstånd av användargränssnittet. Visningsgenereringsdelen av Komponent är ganska intressant och möjligen orsaken till att React sticker ut jämfört med andra ramar. Istället för att bygga en fysisk DOM direkt från en mallfil / skript / funktion, Komponent genererar en mellanliggande DOM som är en stand-in för den verkliga HTML DOM. Ett ytterligare steg tas då för att översätta denna mellanliggande DOM till den verkliga HTML DOM.

Som en del av den mellanliggande DOM-generationen, Komponent Fäster även händelsehanterare och binder data som finns i rekvisita och stat.

Om tanken på en mellanliggande DOM låter lite alien, var inte för orolig. Du har redan sett denna strategi antagen av språk runtime (aka virtuella maskiner) för tolkade språk. Vår egen JavaScript runtime genererar först en mellanrepresentation innan du spitar ut den ursprungliga koden. Detta gäller även för andra VM-baserade språk som Java, C #, Ruby, Python, etc..

React adoptively adopterar denna strategi för att skapa en mellanliggande DOM innan generering av den slutliga HTML DOM. Den mellanliggande DOM är bara ett JavaScript-objektgraf och görs inte direkt. Det finns ett översättningssteg som skapar den verkliga DOM. Detta är den bakomliggande tekniken som gör React att göra snabba DOM-manipulationer.

Reagera i djup

För att få en bättre bild av hur React gör det hela jobbet, låt oss dyka lite djupare; börjar med Komponent. Komponenten är det primära byggstenen i React. Du kan komponera användargränssnittet för din ansökan genom att montera ett träd av komponenter. Varje komponent ger en implementering för göra() metod, där den skapar mellanliggande DOM. Kallelse React.renderComponent () på roten Komponent resulterar i rekursivt att gå ner i komponent-trädet och bygga upp mellanliggande DOM. Den mellanliggande DOM konverteras sedan till den verkliga HTML DOM.


Eftersom den mellanliggande DOM-skapelsen är en integrerad del av komponenten, ger React en bekväm XML-baserad förlängning till JavaScript, kallad JSX, för att bygga komponentträdet som en uppsättning XML-noder. Detta gör det lättare att visualisera och motivera DOM. JSX förenklar också associeringen av händelsehanterare och egenskaper som xml-attribut. Eftersom JSX är ett förlängningsspråk finns det ett verktyg (kommandorad och i webbläsare) för att skapa den slutliga JavaScript. En JSX XML-nod kartläggs direkt till en komponent. Det är värt att påpeka att React fungerar oberoende av JSX och JSX-språket gör det enkelt att skapa mellanliggande DOM.

Tooling

Kärnreaktionsramen kan laddas ner från deras hemsida. Dessutom, för JSX → JS-omvandlingen kan du antingen använda JSXTransformer i webbläsaren eller använda kommandoradsverktyget, som kallas reaktionsverktyg (installerat via NPM). Du behöver en installation av Node.js för att ladda ner den. Kommandoradsverktyget gör att du kan förkompilera JSX-filerna och undvika översättningen i webbläsaren. Detta rekommenderas definitivt om dina JSX-filer är stora eller många i antal.

En enkel komponent

Okej, vi har sett mycket teori hittills, och jag är säker på att du kliar för att se någon riktig kod. Låt oss dyka in i vårt första exempel:

/ ** @jsx React.DOM * / var Simple = React.createClass (getInitialState: function () return count: 0;, handtagMouseDown: function () alert ('Jag fick höra:' + this. props.message); this.setState (count: this.state.count + 1);, render: funktion () returnera 
Ge mig meddelandet!
Meddelandet förmedlas This.state.count tid (s)
; ); React.renderComponent (, document.body);

Även om det är enkelt täcker koden ovan en bra mängd av React-ytan:

  • Vi skapar den enkla komponenten genom att använda React.createClass och passerar i ett objekt som genomför vissa kärnfunktioner. Den viktigaste är den göra(), som genererar mellanliggande DOM.
  • Här använder vi JSX för att definiera DOM och bifogar även mousedown event-handler. De syntax är användbar för att inkorporera JavaScript-uttryck för attribut (onMouseDown = this.handleClick) och barn-noder (This.state.count). Eventhanterare associerade med -syntaxen är automatiskt bundna till förekomsten av komponenten. Således detta Inom händelsehanteringsfunktionen avses komponentinstansen. Kommentaren på första raden / ** @jsx React.DOM * / är en cue för JSX-transformatorn för att göra översättningen till JS. Utan denna kommentarlinje kommer ingen översättning att äga rum.

Vi kan köra kommandoradsverktyget (JSX) i klockläge och automatiskt kompilera ändringar från JSX → JS. Källfilerna finns i / src mappen och utgången genereras i /bygga.

jsx - watch src / build /

Här är den genererade JS-filen:

/ ** @jsx React.DOM * / var Simple = React.createClass (displayName: 'Simple', getInitialState: funktion () return count: 0;, handtagMouseDown: function () alert berättade: '+ this.props.message); this.setState (count: this.state.count + 1);, render: function () return React.DOM.div (null, React.DOM.div (className: "clicker", onMouseDown: this.handleMouseDown, "Ge mig meddelandet!"), React.DOM.div (className: "message", "Meddelande förmedlad", React.DOM.span ( className: "count", this.state.count), "tid (s)"));); React.renderComponent (Simple (message: "Keep it Simple"), document.body);

Lägg märke till hur

och tags map till instanser av React.DOM.div och React.DOM.span.

  • Låt oss nu komma tillbaka till vårt kodexempel. Inuti handleMouseDown, vi använder oss av this.props att läsa meddelande egendom som passerade in. Vi satte in meddelande på sista raden i utdraget, i samtalet till React.renderComponent () där vi skapar komponent. Meningen med this.props är att lagra data som skickades in till komponenten. Det anses vara oföränderligt och endast en högre komponent får göra ändringar och skicka den ner i komponentträdet.
  • Inuti handleMouseDown vi ställer också in vissa användarstatus med this.setState () för att spåra hur många gånger meddelandet visades. Du märker att vi använder this.state i göra() metod. När som helst du ringer sets (), Reakt utlöser också göra() metod för att hålla DOM synkroniserat. Förutom React.renderComponent (), sets () är ett annat sätt att tvinga en visuell uppdatering.

Syntetiska händelser

De händelser som exponeras på mellanliggande DOM, som t.ex. onMouseDown, fungerar också som ett skikt av indirection innan de sätts på den verkliga DOM. Dessa händelser kallas sålunda som Syntetiska händelser. React adopterar händelsesdelegation, som är en välkänd teknik, och fäster händelser bara på root-levelen av real-DOM. Således finns det bara en sann händelsehanterare på real-DOM. Dessutom ger dessa syntetiska händelser en grad av konsistens genom att gömma webbläsar- och elementskillnader.

Kombinationen av mellanliggande DOM och syntetiska händelser ger dig ett vanligt och konsekvent sätt att definiera användargränssnitt över olika webbläsare och till och med enheter.

Komponentlivscykel

Komponenter i React-ramen har en specifik livscykel och utgör en statlig maskin som har tre distinkta tillstånd.


Komponenten kommer till liv efter att ha blivit Monterad. Monteringen resulterar i att gå igenom ett renderingspass som genererar komponent-trädet (mellanliggande DOM). Detta träd konverteras och placeras i en behållare-nod av den verkliga DOM. Detta är ett direkt resultat av samtalet till React.renderComponent ().

När den är monterad, stannar komponenten i Uppdatering stat. En komponent blir uppdaterad när du ändrar tillstånd med sets () eller ändra rekvisita med setProps (). Detta resulterar i sin tur göra(), vilket gör att DOM synkroniseras med data (rekvisita + stat). Mellan följande uppdateringar beräknar React deltaet mellan föregående komponenttree och det nybildade trädet. Detta är ett mycket optimerat steg (och ett flaggskeppsfunktion) som minimerar manipulationen på den verkliga DOM.

Det slutliga tillståndet är omonterad. Detta händer när du uttryckligen ringer React.unmountAndReleaseReactRootNode () eller automatiskt om en komponent var ett barn som inte längre genererades i en göra() ring upp. Oftast behöver du inte ta itu med detta och bara låta React göra rätt.

Nu skulle det ha varit en stor remiss, om React inte berättade när det rörde sig mellan Monterad-Update-Omonterad stater. Lyckligtvis är det inte så, och det finns krokar som du kan åsidosätta för att bli informerad om livscykeländringar. Namnen talar för sig själva:

  • getInitialState (): Förbered initialtillståndet för komponenten
  • componentWillMount ()
  • componentDidMount ()
  • componentWillReceiveProps ()
  • shouldComponentUpdate (): användbar om du vill kontrollera när en rendering ska hoppas över.
  • componentWillUpdate ()
  • göra()
  • componentDidUpdate ()
  • componentWillUnmount ()

De componentWill * metoder kallas innan staten förändras och componentDid * metoderna kallas efter.

Några av metodnamnen verkar ha tagit en cue från kakaoramarna i Mac och iOS

Diverse funktioner

Inom ett komponent-träd bör data alltid strömma ner. En föräldrakomponent ska ställa in rekvisita av en barnkomponent för att överföra data från föräldern till barnet. Detta kallas som Ägare-Owned par. Å andra sidan kommer användarhändelser (mus, tangentbord, berör) alltid att bubbla upp från barnet hela vägen till rotkomponenten, om inte hanteras mellan.


När du skapar mellanliggande DOM i göra(), du kan också tilldela en ref egendom till en barnkomponent. Du kan då hänvisa till det från föräldern med hjälp av refs fast egendom. Detta är avbildat i biten nedan.

 render: funktion () // Ange en återgång 
This.state.count
; handtagMouseDown: funktion () // Använd ref console.log (this.refs.counter.innerHTML); ,

Som en del av komponentmetadata kan du ställa in initialtillståndet (getInitialState ()), som vi såg tidigare inom livscykelmetoderna. Du kan också ställa in standardvärdena för rekvisita med getDefaultProps () och upprätta också några valideringsregler för dessa rekvisita med hjälp av propTypes. Dokumenten ger en fin översikt över de olika typerna av valideringar (typ kontroller, obligatoriska etc.) som du kan utföra.

React stöder också begreppet a Blanda i att extrahera återanvändbara beteenden som kan injiceras i olika komponenter. Du kan skicka mixins med hjälp av mixins egenskap hos en komponent.

Nu kan vi bli verkliga och bygga en mer omfattande komponent som använder dessa funktioner.

En formredigerare som byggdes med hjälp av React

I det här exemplet kommer vi att bygga en redaktör som accepterar en enkel DSL (Domain Specific Language) för att skapa former. När du skriver in kommer du att se motsvarande utdata på sidan, vilket ger dig live feedback.

DSL låter dig skapa tre typer av former: Ellipse, Rektangel och Text. Varje form anges på en separat linje tillsammans med en massa stylingsegenskaper. Syntaxen är okomplicerad och lånar lite från CSS. För att analysera en rad använder vi en Regex som ser ut som:

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

Som ett exempel beskriver följande uppsättning linjer två rektanglar och en textetikett ...

// Reagera etiketttextvärde: React; färg: # 00D8FF; typsnittstorlek: 48px; textskugga: 1px 1px 3px # 555; vaddering: 10px; vänster: 100px; topp: 100px; // left logo rekt bakgrund: url (react.png) no-repeat; gränsen: ingen; bredd: 38; höjd: 38; vänster: 60px; topp: 120px; // rätt logo rekt bakgrund: url (react.png) no-repeat; gränsen: ingen; bredd: 38; höjd: 38; vänster: 250px; topp: 120px;

... genererar produktionen som visas nedan:


Inställning

Okej, låt oss fortsätta och bygga denna redaktör. Vi kommer att börja med HTML-filen (index.html), där vi lägger upp toppnivån och inkluderar bibliotek och applikationsskript. Jag visar bara relevanta delar här:

  

I ovanstående kod, den behållare div håller vår React genererade DOM. Våra applikationsskript ingår från /bygga katalogen. Vi använder JSX inom våra komponenter och kommandoradenJSX), lägger de konverterade JS-filerna in i /bygga. Observera att det här klockarkommandot är en del av reagerar-tools NPM-modulen.

jsx - watch src / build /

Redigeraren är uppdelad i en uppsättning komponenter, som listas nedan:

  • ShapeEditor: Roten Komponent i komponentträdet
  • ShapeCanvas: ansvarig för att generera formen-komponenter (ellips, rektangel, text). Den finns i ShapeEditor.
  • ShapeParser: ansvarig för att tolka text och extrahera listan med formdefinitioner. Det analyserar linje för rad med Regex som vi såg tidigare. Ogiltiga rader ignoreras. Detta är egentligen inte en komponent, utan ett hjälpar JS-objekt som används av ShapeEditor.
  • Ellipse, Rektangel, Text: Formen Komponenter. Dessa blir barn i ShapeCanvas.
  • ShapePropertyMixin: ger hjälparfunktioner för att extrahera stilar som finns i formdefinitionerna. Detta blandas in i de tre formen-komponenterna med hjälp av mixins fast egendom.
  • app: Ingångspunkten för redaktören. Den genererar rotkomponenten (ShapeEditor) och låter dig välja ett formprov från rullgardinsmenyn.

Förhållandet mellan dessa enheter visas i det annoterade komponent-trädet:


ShapeEditor Component

Låt oss titta på implementeringen av några av dessa komponenter, från och med ShapeEditor.

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