Nivelarea cu React: React Router

acest tutorial este primul dintr-o serie de trei părți pe React de Brad Westfall. Când Brad mi-a arătat acest lucru, el a subliniat că există o mulțime de tutoriale despre începerea în React, dar nu la fel de mult despre unde să mergem de acolo. Dacă sunteți nou să reacționați, vă recomand să vizionați acest videoclip introductiv. Această serie preia în cazul în care elementele de bază lasă off.

serie de articole:

  1. React Router (sunteți aici!)
  2. Componente Container
  3. Redux

Atenție! Acest articol a fost scris pre-React Router 4, care a devenit o alegere mai standard pentru rutare în React. Există un nou articol care acoperă React Router 4 aici ar trebui să citiți cu siguranță.

când învățam pentru prima dată, am găsit o mulțime de ghiduri pentru începători (adică 1, 2, 3, 4) care arătau cum să fac componente unice și să le redau domului. Ei au făcut o treabă bună de predare elementele de bază, cum ar fi JSX și recuzită, dar m – am luptat cu imaginind cum funcționează React în imaginea de ansamblu-ca o aplicație unică pagină din lumea reală (SPA). Deoarece această serie acoperă o mulțime de materiale, nu va acoperi conceptele absolute pentru începători. În schimb, va începe cu presupunerea că înțelegeți deja cum să creați și să redați cel puțin o componentă.

pentru ceea ce merită, iată câteva alte ghiduri grozave care vizează începătorii:

  • reacționează.js și cum se potrivește cu orice altceva?
  • Regândirea (Industrie) Cele Mai Bune Practici
  • React.JS introducere pentru cei care știu doar suficient jQuery Pentru a obține de

Cod serie

această serie, de asemenea, vine cu unele Cod să se joace cu la GitHub. De-a lungul seriei, vom construi un SPA de bază axat pe utilizatori și widget-uri.

pentru a păstra lucrurile simple și scurte, exemplele din această serie vor începe prin a presupune că React și React Router sunt preluate de pe un CDN. Deci nu veți vedea require() sau import în exemplele imediate de mai jos. Spre sfârșitul acestui tutorial, însă, vom introduce Webpack și Babel pentru ghidurile GitHub. În acel moment, totul este ES6!

React-Router

React nu este un cadru, este o bibliotecă. Prin urmare, nu rezolvă toate nevoile unei aplicații. Face o treabă excelentă la crearea componentelor și la furnizarea unui sistem de gestionare a statului, dar crearea unui SPA mai complex va necesita o distribuție de sprijin. Primul pe care îl vom analiza este React Router.

dacă ați folosit vreun router front-end înainte, multe dintre aceste concepte vor fi familiare. Dar, spre deosebire de orice alt router pe care l-am folosit înainte, React Router folosește JSX, care ar putea părea puțin ciudat la început.

ca un primer, aceasta este ceea ce este ca pentru a face o singură componentă:

var Home = React.createClass({ render: function() { return (<h1>Welcome to the Home Page</h1>); }});ReactDOM.render(( <Home />), document.getElementById('root'));

Iată cum ar fi redată componenta Home cu routerul React:

...ReactDOM.render(( <Router> <Route path="/" component={Home} /> </Router>), document.getElementById('root'));

rețineți că <Router> și <Route> sunt două lucruri diferite. Ele sunt componente reacționează punct de vedere tehnic, dar ele nu creează de fapt DOM ei înșiși. Deși poate părea că <Router> în sine este redat la 'root', de fapt definim doar reguli despre modul în care funcționează aplicația noastră. Mergând mai departe, veți vedea adesea acest concept: componentele există uneori nu pentru a crea ele însele DOM, ci pentru a coordona alte componente care fac.

în exemplu, <Route> definește o regulă în care vizitarea paginii de pornire / va face componenta Homeîn 'root'.

rute Multiple

în exemplul anterior, traseul unic este foarte simplu. Nu ne dă prea multă valoare, deoarece am avut deja capacitatea de a reda componenta Home fără ca routerul să fie implicat.

puterea routerului React vine atunci când folosim mai multe rute pentru a defini ce componentă ar trebui să redea pe baza căii active în prezent:

ReactDOM.render(( <Router> <Route path="/" component={Home} /> <Route path="/users" component={Users} /> <Route path="/widgets" component={Widgets} /> </Router>), document.getElementById('root'));

fiecare <Route> va reda componenta respectivă atunci când calea sa se potrivește cu adresa URL. Doar una dintre aceste trei componente va fi redată în 'root' la un moment dat. Cu această strategie, montăm routerul la DOM 'root' o dată, apoi componentele de schimb ale routerului intră și ies cu modificări ale rutei.

de asemenea, merită remarcat faptul că routerul va schimba rutele fără a face cereri către server, deci imaginați-vă că fiecare componentă ar putea fi o pagină cu totul nouă.

aspect reutilizabil

începem să vedem începuturile umile ale unei aplicații cu o singură pagină. Cu toate acestea, încă nu rezolvă problemele din lumea reală. Sigur, am putea construi cele trei componente pentru a fi pagini HTML complete, dar ce zici de reutilizarea codului? Șansele sunt, aceste trei componente împărtășesc active comune, cum ar fi un antet și o bară laterală, deci cum prevenim repetarea HTML în fiecare componentă?

să ne imaginăm că construim o aplicație web care seamănă cu această machetă:

un simplu site-ul mockup.

când începeți să vă gândiți la modul în care această machetă poate fi împărțită în secțiuni reutilizabile, s-ar putea să ajungeți la această idee:

cum s-ar putea rupe simplu macheta web în secțiuni.

gândirea în termeni de componente și machete nestabile ne va permite să creăm piese reutilizabile.

dintr-o dată, Departamentul de artă vă permite să știți că aplicația are nevoie de o pagină pentru căutarea widget-uri care seamănă cu pagina pentru căutarea utilizatorilor. Cu lista de utilizatori și lista de Widget-uri care necesită același” aspect ” pentru pagina lor de căutare, ideea de a avea aspectul de căutare ca o componentă separată are și mai mult sens acum:

căutați widgeturi acum, în locul utilizatorilor, dar secțiunile părinte rămân aceleași.

aspect de căutare poate fi un șablon părinte pentru toate tipurile de pagini de căutare acum. Și în timp ce unele pagini ar putea avea nevoie de aspect de căutare, altele pot folosi direct aspectul principal fără ea:

un aspect decuplat.

aceasta este o strategie comună și dacă ați folosit orice sistem templating, ați făcut, probabil, ceva foarte similar. Acum să lucrăm la HTML. Pentru a începe, vom face HTML static fără a lua în considerare JavaScript:

<div> <!-- Main Layout --> <div class="app"> <header class="primary-header"><header> <aside class="primary-aside"></aside> <main> <!-- Search Layout --> <div class="search"> <header class="search-header"></header> <div class="results"> <!-- User List --> <ul class="user-list"> <li>Dan</li> <li>Ryan</li> <li>Michael</li> </ul> </div> <div class="search-footer pagination"></div> </div> </main> </div></div>

amintiți-vă, elementul 'root' va fi întotdeauna prezent, deoarece este singurul element pe care corpul HTML inițial îl are înainte de a începe JavaScript. Cuvântul „rădăcină” este adecvat, deoarece întreaga noastră aplicație React se va monta la ea. Dar nu există „nume corect” sau convenție la ceea ce îl numiți. Am ales „root”, așa că vom continua să-l folosească de-a lungul exemplelor. Aveți grijă doar că montarea directă la elementul <body> este foarte descurajată.

după crearea HTML-ului static, convertiți-l în componente React:

var MainLayout = React.createClass({ render: function() { // Note the `className` rather than `class` // `class` is a reserved word in JavaScript, so JSX uses `className` // Ultimately, it will render with a `class` in the DOM return ( <div className="app"> <header className="primary-header"><header> <aside className="primary-aside"></aside> <main> {this.props.children} </main> </div> ); }});var SearchLayout = React.createClass({ render: function() { return ( <div className="search"> <header className="search-header"></header> <div className="results"> {this.props.children} </div> <div className="search-footer pagination"></div> </div> ); }});var UserList = React.createClass({ render: function() { return ( <ul className="user-list"> <li>Dan</li> <li>Ryan</li> <li>Michael</li> </ul> ); }});

nu vă distrați prea mult între ceea ce numesc „aspect” vs „componentă”. Toate cele trei sunt componente React. Am ales să numesc două dintre ele” machete”, deoarece acesta este rolul pe care îl îndeplinesc.

vom folosi în cele din urmă „rute imbricate” pentru a plasa UserList în interiorul SearchLayout, apoi în interiorul MainLayout. Dar mai întâi, observați că atunci când UserList este plasat în interiorul părintelui său SearchLayout, părintele va folosi this.props.children pentru a determina locația sa. Toate componentele au this.props.children ca recuzită, dar numai atunci când componentele sunt imbricate, componenta părinte primește acest recuzită completat automat de React. Pentru componentele care nu sunt componente părinte, this.props.children va fi null.

rute imbricate

Deci, cum facem ca aceste componente să cuibărească? Routerul o face pentru noi când cuibărim rute:

ReactDOM.render(( <Router> <Route component={MainLayout}> <Route component={SearchLayout}> <Route path="users" component={UserList} /> </Route> </Route> </Router>), document.getElementById('root'));

componentele vor fi imbricate în funcție de modul în care routerul își cuibărește rutele. Când utilizatorul vizitează ruta /users, ruterul React va plasa componenta UserList în interiorul SearchLayoutși apoi ambele în interiorul MainLayout. Rezultatul final al vizitei /usersva fi cele trei componente imbricate plasate în interiorul 'root'.

observați că nu avem o regulă pentru momentul în care utilizatorul vizitează calea paginii de pornire (/) sau dorește să caute widget-uri. Acestea au fost lăsate în afara simplității, dar să le punem cu noul router:

ReactDOM.render(( <Router> <Route component={MainLayout}> <Route path="/" component={Home} /> <Route component={SearchLayout}> <Route path="users" component={UserList} /> <Route path="widgets" component={WidgetList} /> </Route> </Route> </Router>), document.getElementById('root'));

probabil ați observat până acum că JSX urmează regulile XML în sensul că componenta Route poate fi scrisă fie ca o etichetă: <Route />, fie ca două: <Route>...</Route>. Acest lucru este valabil pentru toate JSX, inclusiv componentele personalizate și nodurile DOM normale. De exemplu, <div /> este JSX valid și se va converti la <div></div> când este redat.

pentru concizie, imaginați-vă WidgetListseamănă cu UserList.

deoarece <Route component={SearchLayout}> are două rute pentru copii acum, utilizatorul poate vizita /users sau /widgets și <Route> corespunzător își va încărca componentele respective în interiorul componentei SearchLayout.

de asemenea, observați cum componenta Home va fi plasată direct în MainLayout fără ca SearchLayoutsă fie implicată — din cauza modului în care <Route> sunt imbricate. Probabil vă puteți imagina că este ușor să rearanjați modul în care aspectele și componentele sunt imbricate prin rearanjarea rutelor.

IndexRoutes

React Router este foarte expresiv și de multe ori există mai multe moduri de a face același lucru. De exemplu, am fi putut scrie și routerul de mai sus astfel:

ReactDOM.render(( <Router> <Route path="/" component={MainLayout}> <IndexRoute component={Home} /> <Route component={SearchLayout}> <Route path="users" component={UserList} /> <Route path="widgets" component={WidgetList} /> </Route> </Route> </Router>), document.getElementById('root'));

în ciuda aspectului său diferit, ambele funcționează exact în același mod.

atribute opționale de traseu

uneori, <Route> va avea un atribut component fără path, ca în SearchLayout traseu de sus. Alteori, ar putea fi necesar să avem un <Route> cu un path și nu component. Pentru a vedea de ce, să începem cu acest exemplu:

<Route path="product/settings" component={ProductSettings} /><Route path="product/inventory" component={ProductInventory} /><Route path="product/orders" component={ProductOrders} />

porțiunea /product a path este repetitivă. Putem elimina repetarea prin împachetarea tuturor celor trei rute într – o nouă <Route>:

<Route path="product"> <Route path="settings" component={ProductSettings} /> <Route path="inventory" component={ProductInventory} /> <Route path="orders" component={ProductOrders} /></Route>

din nou, React Router își arată expresivitatea. Quiz: ați observat problema cu ambele soluții? În acest moment nu avem reguli pentru momentul în care utilizatorul vizitează calea /product.

pentru a remedia acest lucru, putem adăuga un IndexRoute:

<Route path="product"> <IndexRoute component={ProductProfile} /> <Route path="settings" component={ProductSettings} /> <Route path="inventory" component={ProductInventory} /> <Route path="orders" component={ProductOrders} /></Route>

utilizați <Link> nu <a>

când creați ancore pentru rutele dvs., va trebui să utilizați <Link to="">în loc de <a href="">. Nu vă faceți griji, totuși, atunci când utilizați componenta <Link>, routerul React vă va oferi în cele din urmă o ancoră obișnuită în DOM. Utilizarea <Link> deși este necesar pentru React Router pentru a face o parte din magia de rutare.

să adăugăm niște legături (ancore) la MainLayout:

var MainLayout = React.createClass({ render: function() { return ( <div className="app"> <header className="primary-header"></header> <aside className="primary-aside"> <ul> <li><Link to="/">Home</Link></li> <li><Link to="/users">Users</Link></li> <li><Link to="/widgets">Widgets</Link></li> </ul> </aside> <main> {this.props.children} </main> </div> ); }});

atributele componentelor <Link> vor fi transmise către ancora pe care o creează. Deci acest JSX:

<Link to="/users" className="users">

va deveni acest lucru în DOM:

<a href="/users" class="users">

dacă trebuie să creați o ancoră pentru căi non-router, cum ar fi un site web extern, utilizați etichetele normale de ancorare ca de obicei. Pentru mai multe informații, consultați documentația pentru IndexRoute și Link.

link-uri Active

o caracteristică interesantă a componentei <Link> este capacitatea sa de a ști când este activă:

<Link to="/users" activeClassName="active">Users</Link>

dacă utilizatorul se află pe calea /users, routerul va căuta ancore potrivite care au fost realizate cu <Link> și va comuta clasa lor active. Vezi mai multe despre această caracteristică.

istoricul browserului

pentru a preveni confuzia, am omis un detaliu important până acum. <Router> trebuie să știe ce strategie de urmărire a istoricului să folosească. React Router docs recomandă browserHistory care este implementat după cum urmează:

var browserHistory = ReactRouter.browserHistory;ReactDOM.render(( <Router history={browserHistory}> ... </Router>), document.getElementById('root'));

în versiunile anterioare ale React Router, history atribut nu a fost necesară și implicit a fost de a utiliza hashHistory. După cum sugerează și numele, a folosit un semn hash # în adresa URL pentru a gestiona rutarea în stil SPA front-end, similar cu ceea ce v-ați putea aștepta de la o coloană vertebrală.JS router.

cu hashHistory, adresele URL vor arăta astfel:

  • example.com
  • example.com/#/users?_k=ckuvup
  • example.com/#/widgets?_k=ckuvup

ce se întâmplă cu acele șiruri de interogare urâte?

când browserHistory este implementat, căile arată mai organic:

  • example.com
  • example.com/users
  • exemplu.com / widgets

există un avertisment, deși pe server atunci când browserHistory este utilizat pe front-end. Dacă utilizatorul își începe vizita la example.com și apoi navighează la /users și /widgets, React Router gestionează acest scenariu așa cum era de așteptat. Cu toate acestea, dacă utilizatorul își începe vizita tastând example.com/widgets direct în browser sau dacă se actualizează pe example.com/widgets, atunci browserul trebuie să facă cel puțin o solicitare către server pentru /widgets. Dacă nu există un router server-side, deși, acest lucru va livra o 404:

aveți grijă cu adresele URL. Veți avea nevoie de un router pe partea de server.

pentru a rezolva problema 404 de pe server, React Router recomandă un router wildcard pe partea de server. Cu această strategie, indiferent de ruta server-side se numește, serverul ar trebui să servească întotdeauna același fișier HTML. Apoi, dacă utilizatorul pornește direct la example.com/widgets, chiar dacă același fișier HTML este returnat, React Router este suficient de inteligent pentru a încărca componenta corectă.

utilizatorul nu va observa nimic ciudat, dar este posibil să aveți îngrijorări cu privire la servirea întotdeauna a aceluiași fișier HTML. În exemplele de cod, această serie va continua să utilizeze strategia „router wildcard”, dar depinde de dvs. să gestionați rutarea de pe server în moduri pe care le considerați potrivite.

routerul React poate fi utilizat atât pe partea de server, cât și pe partea de client într-un mod izomorf? Sigur că se poate, dar asta depășește cu mult domeniul de aplicare al acestui tutorial.

redirecționare cu browserHistory

browserHistory obiectul este un singleton, astfel încât să îl puteți include în oricare dintre fișierele dvs. Dacă trebuie să redirecționați manual utilizatorul în oricare dintre codul dvs., puteți utiliza metoda push pentru a face acest lucru:

browserHistory.push('/some/path');

potrivirea rutelor

routerul React gestionează potrivirea rutelor în mod similar cu alte routere:

<Route path="users/:userId" component={UserProfile} />

acest traseu se va potrivi atunci când utilizatorul vizitează orice cale care începe cu users/ și are orice valoare după aceea. Se va potrivi cu /users/1, /users/143 sau chiar /users/abc (pe care va trebui să îl validați singur).

React Router va trece valoarea pentru :userId ca recuzită la UserProfile. Această recuzită este accesată ca this.props.params.userIdîn interiorul UserProfile.

Router Demo

în acest moment, avem suficient cod pentru a afișa un demo.

a se vedea Pen React-Router Demo de Brad Westfall (@bradwestfall) pe CodePen.

dacă ați făcut clic pe câteva rute din exemplu, este posibil să observați că butoanele Înapoi și înainte ale browserului funcționează cu routerul. Acesta este unul dintre principalele motive pentru care există aceste strategii history. De asemenea, rețineți că, cu fiecare traseu pe care îl vizitați, nu există solicitări către server, cu excepția primului care obține codul HTML inițial. Cât de tare e asta?

ES6

în exemplul CodePen, React, ReactDOM și ReactRouter sunt variabile globale dintr-un CDN. În interiorul obiectului ReactRouter sunt tot felul de lucruri de care avem nevoie, cum ar fi componentele Router și Route. Deci, am putea folosi ReactRouter ca aceasta:

ReactDOM.render(( <ReactRouter.Router> <ReactRouter.Route ... /> </ReactRouter.Router>), document.getElementById('root'));

aici, trebuie să prefixăm toate componentele routerului nostru cu obiectul părinte ReactRouter. Sau am putea folosi noua sintaxă destructuring ES6 ca aceasta:

var { Router, Route, IndexRoute, Link } = ReactRouter

aceasta „extrage” părți din ReactRouter în variabile normale, astfel încât să le putem accesa direct.

începând de acum, exemplele din această serie vor folosi o varietate de sintaxe ES6, inclusiv destructurarea, operatorul de răspândire, importurile/exporturile și, probabil, altele. Va exista o scurtă explicație a fiecărei noi sintaxe pe măsură ce apar, iar repo-ul GitHub care vine cu această serie are, de asemenea, o mulțime de explicații ES6.

gruparea cu webpack și Babel

după cum sa menționat anterior, această serie vine cu un repo GitHub astfel încât să puteți experimenta cu cod. Deoarece se va asemăna cu crearea unui SPA din lumea reală, va folosi instrumente precum webpack și Babel.

  • webpack grupează mai multe fișiere JavaScript într-un singur fișier pentru browser.
  • Babel va converti codul ES6 (ES2015) în ES5, deoarece majoritatea browserelor nu înțeleg încă toate ES6. Ca acest articol vârstele, browsere va sprijini ES6 și Babel nu pot fi necesare.

dacă nu sunteți încă prea confortabil folosind aceste instrumente, nu vă faceți griji, Codul De exemplu are deja totul de configurare, astfel încât să vă puteți concentra pe React. Dar asigurați – vă că pentru a revizui codul de exemplu README.md fișier pentru documentația suplimentară a fluxului de lucru.

aveți grijă la sintaxa depreciată

căutarea pe Google a informațiilor despre routerul React vă poate ateriza pe unul dintre numeroasele articole sau pagini StackOverflow care au fost scrise când routerul React a fost în versiunea sa pre-1.0. Multe caracteristici din pre-1.0 eliberare sunt depreciate acum. Iată o listă scurtă:

  • <Route name="" /> este învechit. Utilizați <Route path="" /> în schimb.
  • <Route handler="" /> este învechit. Utilizați <Route component="" /> în schimb.
  • <NotFoundRoute /> este învechit. A se vedea alternativa
  • <RouteHandler /> este învechită.
  • willTransitionTo este învechit. A se vedea onEnter
  • willTransitionFrom este învechit. A se vedea onLeave
  • „locații” sunt acum numite „istorii”.

a se vedea lista completă pentru 1.0.0 și 2.0.0

rezumat

există încă mai multe caracteristici în React Router care nu au fost afișate, astfel încât să fie sigur de a verifica documentele API. Creatorii React Router au creat, de asemenea, un tutorial pas cu pas pentru React Router și, de asemenea, checkout acest React.JS Conf Video despre modul în care a fost creat React Router.

Mulțumiri speciale lui Lynn Fisher pentru opera de artă @lynnandtonic

serie de articole:

  1. React Router (sunteți aici!)
  2. Componente Container
  3. Redux

Lasă un răspuns

Adresa ta de email nu va fi publicată.