În lumea de astăzi a cadrelor de aplicații Javascript, filosofia de design este factorul de diferențiere cheie. Dacă comparați cadrele populare JS, cum ar fi EmberJS, AngularJS, Backbone, Knockout, etc., veți găsi cu siguranță diferențe în abstracții, modele de gândire și, bineînțeles, în terminologie. Aceasta este o consecință directă a filozofiei de design de bază. Dar, în principiu, toți fac un lucru, care este de a abroga DOM în așa fel încât să nu tratezi direct elemente HTML.
Eu personal cred că un cadru devine interesant atunci când oferă un set de abstracții care permit un mod diferit de gândire. În acest aspect, reacționați, noul cadru JS de la cei de la Facebook, vă va obliga să regândiți (într-o anumită măsură) modul în care vă descompuneți interfața și interacțiunile aplicației dvs. După ce a ajuns la versiunea 0.4.1 (de la această scriere), React oferă un model surprinzător de simplu, dar eficient pentru construirea de aplicații JS care amestecă un cocktail încântător de alt tip.
În acest articol, vom explora elementele de bază ale Reactului și vom îmbrățișa un stil de gândire care ar putea părea contra-intuitiv la prima ieșire. Dar, așa cum spun documentele React: "Dați-i cinci minute" și apoi veți vedea cum această abordare va deveni mai naturală.
Povestea lui React a început în limitele Facebook, unde a fost preparată o perioadă de timp. După ce a ajuns la o stare stabilă, dezvoltatorii au decis să-l deschidă cu câteva luni în urmă. În mod interesant, site-ul Instagram este, de asemenea, alimentat de React Framework.
Reacția abordează problema DOM-abstractizare cu o preluare ușor diferită. Pentru a înțelege cum este diferit acest lucru, vă permite să luați rapid luciu asupra tehnicilor adoptate de cadrele menționate anterior.
Modelul de design MVC (Model-View-Controller) este fundamental pentru dezvoltarea UI, nu doar în aplicațiile web, ci și în aplicațiile de pe orice platformă. În cazul aplicațiilor web, DOM este reprezentarea fizică a unei Vizualizări. DOM-ul în sine este generat dintr-un șablon textual html care este tras de la un alt fișier, un script-bloc sau o funcție de șablon precomplicat. Vedere
este o entitate care aduce șablonul textual la viață ca fragment DOM. De asemenea, stabilește procesatori de evenimente și are grijă de manipularea copacului DOM în cadrul ciclului său de viață.
Pentru Vedere
pentru a fi util, trebuie să arate anumite date și, eventual, să permită interacțiunea cu utilizatorul. Datele sunt Model
, care provine de la o sursă de date (o bază de date, serviciu web, stocare locală etc.). Cadrele oferă o modalitate de "legare" a datelor către vizualizare, astfel încât modificările datelor să se reflecte automat cu modificările din vizualizare. Acest proces automat este chemat Datele de legare și există API-uri / tehnici pentru a face acest lucru cât mai perfect posibil.
Trilul MVC este completat de Controlor
, care angajează Vedere
si Model
și orchestrează fluxul de date (Model
) în Vedere
și evenimentele utilizatorilor afară din Vedere
, ceea ce ar putea conduce la schimbări în Model
.
Cadrele care gestionează automat fluxul de date înainte și înapoi între vizualizare și model mențin o buclă internă de evenimente. Această buclă de evenimente este necesară pentru a asculta anumite evenimente ale utilizatorilor, evenimente de schimbare a datelor, declanșatoare externe etc. și apoi a determina dacă există o schimbare față de rularea anterioară a buclă. Dacă există modificări, la fiecare capăt (Vizualizare sau Model), cadrul asigură că ambele sunt readuse în sincronizare.
Cu React, partea de vizualizare a triadei MVC este proeminentă și este rulată într-o entitate numită component
. Componenta menține un sac de proprietate imuabil numit recuzită
, și a stat
care reprezintă starea ghidată de utilizator a interfeței utilizator. Partea de generare a vederilor din component
este destul de interesant și, eventual, motivul pentru care React se remarcă în comparație cu alte cadre. În loc să construiți un DOM fizic direct dintr - un fișier de șablon / script / funcție, component
generează un DOM intermediar care este un stand-in pentru DOM HTML real. Un pas suplimentar este apoi luat pentru a traduce acest DOM intermediar în DOM HTML real.
Ca parte a generației DOM intermediare, component
atașează de asemenea administratorii de evenimente și leagă datele conținute în recuzită
și stat
.
Dacă ideea unui DOM intermediar pare puțin străin, nu fi prea alarmat. Ați văzut deja această strategie adoptată prin runtime de limbă (aka mașini virtuale) pentru limbile interpretate. Timpul de execuție JavaScript propriu, generează mai întâi o reprezentare intermediară înainte de a scuipa codul nativ. Acest lucru este valabil și pentru alte limbi bazate pe VM, cum ar fi Java, C #, Ruby, Python etc..
Reactați adoptați inteligent această strategie pentru a crea un DOM intermediar înainte de a genera HTML DOM final. Intermediarul-DOM este doar un grafic de obiect JavaScript și nu este redat direct. Există un pas de traducere care creează DOM real. Aceasta este tehnica care face ca React să facă manipulări rapide ale DOM.
Pentru a obține o imagine mai bună a modului în care React face ca totul să funcționeze, hai să ne aruncăm puțin mai adânc; începând cu component
. Componenta este blocul principal de construcție din React. Puteți compune interfața utilizator a aplicației dvs. prin asamblarea unui arbore al Componentelor. Fiecare componentă oferă o implementare pentru face()
unde creează DOM intermediar. apel React.renderComponent ()
pe componenta rădăcină rezultă că se coboară în mod recursiv în josul copacului Component și se construiește DOM intermediar. Intermediarul DOM este apoi convertit în DOM HTML real.
Deoarece crearea intermediare DOM este o parte integrantă a Componentei, React oferă o extensie convenabilă bazată pe XML pentru JavaScript, numită JSX, pentru a construi arborele component ca un set de noduri XML. Acest lucru facilitează vizualizarea și raționamentul despre DOM. De asemenea, JSX simplifică asocierea gestionatorilor de evenimente și a proprietăților ca atribute xml. Deoarece JSX este un limbaj de extensie, există un instrument (linia de comandă și browserul) pentru a genera JavaScript final. Un nod XML JSX se hartă direct către o componentă. Merită să subliniem faptul că React funcționează independent de JSX, iar limbajul JSX face mai ușor crearea DOM-ului intermediar.
Cadrul de bază React poate fi descărcat de pe site-ul lor. În plus, pentru transformarea JSX → JS, puteți utiliza JSXTransformer în browser sau utilizați instrumentul de linie de comandă, numit react-tools (instalat prin NPM). Veți avea nevoie de o instalare a Node.js pentru al descărca. Instrumentul pentru linia de comandă vă permite să precompilați fișierele JSX și să evitați traducerea în browser. Acest lucru este recomandat cu siguranta daca fisierele JSX sunt mari sau numeroase.
În regulă, am văzut o mulțime de teorii până acum și sunt sigur că vă simțiți mâncând să vedeți niște coduri reale. Să ne aruncăm în primul exemplu:
/ ** @jsx React.DOM * / var Simplu = React.createClass (getInitialState: function () return count: 0; handleMouseDown: function () alert (' proset.message); this.setState (count: this.state.count + 1);, render: function () return; ); React.renderComponent (Dă-mi mesajul!Mesaj transmis This.state.count timp (s), document.body);
Deși simplu, codul de mai sus acoperă o cantitate bună din suprafața React:
React.createClass
și trecerea într-un obiect care implementează unele funcții de bază. Cea mai importantă este face()
, care generează DOM intermediar.
sintaxa este utilă pentru includerea expresiilor JavaScript pentru atribute (onmousedown = this.handleClick
) și nodurile copilului (This.state.count
). Manipulatoarele de evenimente asociate folosind sintaxa sunt legate automat de instanța componentei. Prin urmare acest
în interiorul funcției de manipulare a evenimentului se referă la instanța componentei. Comentariul pe prima linie / ** @jsx React.DOM * /
este un semn pentru transformatorul JSX de a face traducerea către JS. Fără această linie de comentarii, nu va avea loc o traducere. Putem rula instrumentul de linie de comandă (jsx) în modul de vizionare și de a compila automat modificările de la JSX → JS. Fișierele sursă sunt în / src folder și ieșirea este generată în /construi.
jsx -watch src / build /
Iată fișierul JS generat:
/ ** @jsx React.DOM * / var Simplu = React.createClass (displayName: 'Simple', getInitialState: function () return count: 0; handleMouseDown: (count: this.state.count + 1);, render: function () return React.DOM.div (null, React.DOM.div) (className: "clicker", onMouseDown: this.handleMouseDown, "Dă-mi mesajul!"), React.DOM.div ( className: "numără", acest număr de stat), "timp (e)"));); React.renderComponent (simplu (message: "Keep it Simple"), document.body);
Observați cum și
tag-uri hartă la instanțe de
React.DOM.div
și React.DOM.span
.
handleMouseDown
, noi facem uz de this.props
pentru a citi mesaj proprietate care a fost trecută. Am stabilit mesaj pe ultima linie a fragmentului, la apelul către React.renderComponent ()
unde creăm
componentă. Scopul de this.props
este de a stoca datele care au fost transmise componentei. Este considerată imuabilă și numai o componentă de nivel superior este permisă să facă schimbări și să o trimită pe arborele component.handleMouseDown
am stabilit, de asemenea, unele state de utilizator cu this.setState ()
pentru a urmări numărul de afișări ale mesajului. Veți observa că vom folosi this.state
în face()
metodă. Oriunde suni setState ()
, Reacția declanșează de asemenea face()
pentru a menține DOM în sincronizare. in afara de asta React.renderComponent ()
, setState ()
este un alt mod de a forța o reîmprospătare vizuală.Evenimentele expuse pe DOM-intermediare, cum ar fi onmousedown
, de asemenea, acționează ca un strat de indirecție înainte ca acestea să fie stabilite pe real-DOM. Aceste evenimente sunt denumite astfel Evenimente sintetice. React adoptă delegarea evenimentelor, o tehnică bine cunoscută și atașează evenimente doar la nivelul rădăcinilor real-DOM. Astfel, există un singur adevărat manipulator de evenimente pe DOM-ul real. În plus, aceste evenimente sintetice oferă și un nivel de consistență prin ascunderea diferențelor de browser și elemente.
Combinația evenimentelor intermediare-DOM și sintetice vă oferă o modalitate standard și coerentă de a defini UI-urile pe diferite browsere și chiar pe dispozitive.
Componentele din cadrul React au un ciclu de viață specific și incorporează o mașină de stat care are trei stări distincte.
Componenta vine la viață după ce a fost Montat. Rezultatele de asamblare duc la trecerea printr-o render-pass care generează arborele component (intermediar-DOM). Acest arbore este transformat și plasat într-un nod de containere al DOM real. Acesta este un rezultat direct al apelului către React.renderComponent ()
.
Odată montat, componenta rămâne în Actualizați stat. O componentă se actualizează atunci când schimbați statul folosind setState ()
sau schimbarea elementelor de recuzită folosind setProps ()
. Aceasta, la rândul său, are ca rezultat chemarea face()
, care aduce DOM în sincronizare cu datele (recuzită
+ stat
). Între actualizările ulterioare, React va calcula delta dintre arborele componente anterior și arborele nou generat. Acesta este un pas foarte optimizat (și o caracteristică emblematică) care minimizează manipularea pe DOM real.
Starea finală este nemontat. Acest lucru se întâmplă când apelați în mod explicit React.unmountAndReleaseReactRootNode ()
sau automat dacă o componentă era un copil care nu mai era generat într-un face()
apel. Cel mai adesea nu trebuie să vă ocupați de acest lucru și lăsați-l pe React să facă ceea ce trebuie.
Acum ar fi fost un mare remiss, dacă React nu ți-a spus când sa mutat între Montat-update-nemontat state. Din fericire, nu este cazul și există cârlige pe care le puteți suprascrie pentru a obține notificări despre modificările ciclului de viață. Numele vorbesc de la sine:
getInitialState ()
: pregătiți starea inițială a ComponenteicomponentWillMount ()
componentDidMount ()
componentWillReceiveProps ()
shouldComponentUpdate ()
: util dacă doriți să controlați când o răsunet ar trebui să fie omisă. componentWillUpdate ()
face()
componentDidUpdate ()
componentWillUnmount ()
componentWill *
metodele sunt numite înainte de schimbarea de stat și de componentDid *
metode sunt numite după.
Într-un arbore component, datele trebuie să scadă întotdeauna. O componentă părinte trebuie să stabilească recuzită
a unei componente copil pentru a transmite orice date de la părinte copilului. Acesta este denumit Owned-proprietar pereche. Pe de altă parte, evenimentele utilizatorilor (mouse-ul, tastatura, atingetele) vor fi întotdeauna bulate de la copil până la componenta rădăcină, dacă nu sunt manipulate între.
Când creați DOM intermediar în face()
, puteți de asemenea să atribuiți ref
proprietate asupra unei componente a copilului. Apoi puteți să vă referiți la acesta de la părinte folosind ref
proprietate. Acesta este descris în fragmentul de mai jos.
render: function () // Setați returul refThis.state.count; handleMouseDown: function () // Utilizați ref console.log (this.refs.counter.innerHTML); ,
Ca parte a metadatelor componente, puteți seta starea inițială (getInitialState ()
), pe care am văzut-o mai devreme în cadrul metodelor ciclului de viață. De asemenea, puteți seta valorile implicite ale recuzităilor cu getDefaultProps ()
și, de asemenea, să stabilească anumite reguli de validare a acestor elemente de recuzită propTypes
. Documentele oferă o imagine de ansamblu frumoasă a diferitelor tipuri de validări (verificări de tip, necesare, etc.) pe care le puteți efectua.
React sprijină, de asemenea, conceptul de a mixin pentru a extrage bucăți reutilizabile de comportament care pot fi injectate în Componente disparate. Puteți trece amestecurile folosind mixins
proprietatea unei Componente.
Acum, permiteți-vă să deveniți real și construiți o Componentă mai cuprinzătoare care utilizează aceste funcții.
În acest exemplu, vom construi un editor care acceptă un simplu DSL (Domain Specific Language) pentru crearea de forme. Pe măsură ce tastați, veți vedea ieșirea corespunzătoare din lateral, oferindu-vă feedback în timp real.
DSL vă permite să creați trei tipuri de forme: Ellipse, Rectangle și Text. Fiecare formă este specificată pe o linie separată împreună cu o grămadă de proprietăți de styling. Sintaxa este simplă și împrumută puțin de la CSS. Pentru a analiza o linie, folosim un Regex care arată ca:
var formaRegex = / (rect | ellipse | text) (\ s [a-z] +: \ s [a-z0-9] +;) * / i;
De exemplu, următorul set de linii descrie două dreptunghiuri și o etichetă de text ...
// Reacționează valoarea textului etichetei: React; culoare: # 00D8FF; font-size: 48px; text-shadow: 1px 1px 3px # 555; padding: 10px; stânga: 100px; top: 100px; // left logo rect fundal: url (react.png) no-repeat; frontieră: nici una; lățime: 38; înălțime: 38; stânga: 60px; top: 120px; // dreapta logo-ul rect logo: url (react.png) no-repeat; frontieră: nici una; lățime: 38; înălțime: 38; stânga: 250px; top: 120px;
... generând rezultatul indicat mai jos:
Bine, dă-i drumul și construiește acest editor. Vom începe cu fișierul HTML (index.html
), unde am introdus marcajul de nivel superior și includem bibliotecile și scripturile de aplicație. Am prezentat doar părțile relevante aici:
În fragmentul de mai sus, recipient
div păstrează DOM-ul nostru generat de React. Scripturile noastre de aplicație sunt incluse în /construi
director. Folosim JSX în cadrul componentelor noastre și observatorul liniei de comandă (jsx
), pune fișierele JS convertite /construi
. Rețineți că această comandă de observator face parte din reacționează-unelte
Modulul NPM.
jsx -watch src / build /
Editorul este defalcat într-un set de componente, care sunt enumerate mai jos:
mixins
proprietate.Relația dintre aceste entități este afișată în arborele componente adnotat:
Să examinăm punerea în aplicare a unora dintre aceste componente, începând cu ShapeEditor.
/ ** @jsx React.DOM * / var ShapeEditor = React.createClass (componentWillMount: function () this._parser = noua ShapeParser ();, getInitialState: render: function () var shapes = this._parser.parse (acest.state.text); var tree = (); retur copac; , handleTextChange: funcție (eveniment) this.setState (text: event.target.value);
După cum sugerează și numele, ShapeEditor oferă experiența de editare generând și feedback-ul live pe
cu privire la schimbările
eveniment (evenimentele din React sunt denumite întotdeauna cu caz de cămilă) pe și la fiecare schimbare, stabilește
text
proprietatea componentei stat
. Așa cum am menționat mai devreme, de fiecare dată când setați statul folosind setState ()
, render se numește automat. În acest caz, face()
din ShapeEditor este numit unde analizăm textul din stat și reconstruim formele. Rețineți că începem cu o stare inițială de text gol, care este setat în getInitialState ()
cârlig.
Pentru parsarea textului într - un set de forme, utilizăm o instanță a ShapeParser
. Am lăsat detaliile parserului pentru a menține discuția pe React. Exemplu parser este creat în componentWillMount ()
cârlig. Aceasta se numește chiar înainte ca componenta să se monteze și este un loc bun pentru a face orice inițializări înainte ca prima renderare să se întâmple.
În general, este recomandat să vă plictisiți toată procesarea complexă prin face()
metodă. Operatorii de evenimente au setat starea în timp face()
este centrul pentru toate logica dvs. de bază.
ShapeEditor
folosește această idee pentru a face parsarea în interiorul ei face()
și înaintează formele detectate prin setarea forme
proprietate a ShapeCanvas
. Acesta este modul în care datele se strecoară în copacul component, de la proprietar (ShapeEditor
) către proprietarul (ShapeCanvas
).
Un ultim lucru de observat aici este că avem primul comentariu pentru a indica traducerea JSX → JS.
Apoi, vom trece la componentele ShapeCanvas și Ellipse, Rectangle și Text.
p> ShapeCanvas
este destul de simplă, cu responsabilitatea sa principală de a genera respectivul
,
și
componente din definițiile adoptate (this.props.shapes
). Pentru fiecare formă, trecem în proprietățile parsate cu expresia atributului: Proprietăți = shape.properties
.
/ ** @jsx React.DOM * / var ShapeCanvas = React.createClass (getDefaultProps: function () return forme: [];this.props.shapes.map (funcția (s) return self._createShape (s);; var noTree =Nu au fost găsite forme; returnați acest.props.shapes.length> 0? shapeTree: noTree; , _createShape: funcția (forma) return this._shapeMap [shape.type] (shape); , _shapeMap: elipsă: funcție (formă) retur; , rect: funcție (formă) retur ; , text: funcție (formă) retur ; );
Un lucru diferit aici este faptul că arborele nostru component nu este static, așa cum îl avem în ShapeEditor. În schimb, este generat în mod dinamic prin looping peste formele transmise. Mai arătăm și "Nicio formă nu a fost găsită"
dacă nu există nimic de arătat.
Toate formele au o structură similară și diferă doar în stil. Ei folosesc de asemenea ShapePropertyMixin
pentru a gestiona generarea stilului.
Iată Ellipse:
/ ** @jsx React.DOM * / var Ellipse = React.createClass (mixins: [ShapePropertyMixin], render: function () var style = this.extractStyle (true) 50% 50% "; ; );
Implementarea pentru extractStyle ()
este furnizat de către ShapePropertyMixin
.
Componenta dreptunghiulară urmează exemplul, desigur fără border-radius stil. Componenta Text are o proprietate suplimentară numită valoare
care stabilește textul interior pentru .
Iată textul, pentru a clarifica acest lucru:
/ ** @jsx React.DOM * / var Text = React.createClass (mixins: [ShapePropertyMixin], render: function () var style = this.extractStyle (false);This.props.properties.value; );
app.js
este locul în care îl aducem împreună. Aici facem componenta rădăcină, ShapeEditor
și oferă, de asemenea, suport pentru a comuta între câteva forme de eșantion. Atunci când alegeți o altă mostră din drop - down, încărcați un text predefinit în ShapeEditor
și provocați ShapeCanvas
a updata. Acest lucru se întâmplă în readShapes ()
metodă.
/ ** @jsx React.DOM * / var formaEditor =; React.renderComponent (shapeEditor, document.getElementsByClassName ('container') [0]); (*) editorul valului (text); formEditor.setState (filename = $ (' text: text); // forțați o render $ ('.formes-picker') schimbare (readShapes); readShapes (); // timpul de încărcare
Pentru a exersa partea creativă, aici este un robot construit folosind editorul Shape:
Pfiu! Acesta a fost un articol destul de lung și după ce ați ajuns la acest punct, ar trebui să aveți un sentiment de realizare!
Am explorat o mulțime de concepte aici: rolul integral al componentelor în cadrul, utilizarea lui JSX pentru a descrie cu ușurință un arbore component (aka intermediar-DOM), diverse cârlige pentru conectarea la componenta de viață a componentelor, utilizarea stat
și recuzită
pentru a conduce procesul de redare, folosirea Mixins pentru a determina comportamentul refolosibil și, în final, trageți toate acestea împreună cu exemplul Editor Shape.
Sper că acest articol vă oferă suficienți stimulenți pentru a crea câteva aplicații React pentru dvs. Pentru a continua explorarea, iată câteva linkuri utile: