Leveling opp Med React: React Router

denne opplæringen Er den første Av en tredelt serie På React Av Brad Westfall. Når Brad slo meg dette, han påpekte at det er en god mengde tutorials på å komme i Gang I React, men ikke så mye om hvor du skal gå derfra. Hvis Du er helt ny Til Å Reagere, anbefaler jeg å se denne introvideoen. Denne serien plukker opp der det grunnleggende la av.

Artikkelserier:

  1. React Router (Du er her !)
  2. Containerkomponenter
  3. Redux

Advarsel! Denne artikkelen ble skrevet pre-React Router 4, som har blitt et mer standardvalg for ruting I React. Det er en ny artikkel som dekker React Router 4 her bør du definitivt lese.

Da jeg først lærte, fant jeg mange nybegynnerguider (dvs. 1, 2, 3, 4) som viste hvordan man lager enkeltkomponenter og gjør DEM TIL DOM. De gjorde en fin jobb med å lære det grunnleggende SOM JSX og rekvisitter, men jeg slet med å finne ut hvordan React fungerer i det større bildet-som en real-world Single Page Application (SPA). Siden denne serien dekker mye materiale, vil den ikke dekke de absolutte nybegynnerkonseptene. I stedet vil det starte med antagelsen om at du allerede forstår hvordan du lager og gjengir minst en komponent.

for hva det er verdt, her er noen andre flotte guider som tar sikte på nybegynnere:

  • Reagere.js og Hvordan Passer Det Inn Med Alt annet?
  • Rethinking (Industri) Beste Praksis
  • Reagere.Js Introduksjon For Folk Som Kjenner Akkurat nok jQuery Til Å Komme Forbi

Seriekode

denne serien kommer også med noen kode for å leke med På GitHub. Gjennom hele serien skal vi bygge et grunnleggende SPA fokusert rundt brukere og widgets.

for å holde ting enkelt og kort, vil eksemplene i denne serien starte med å anta At React and React Router hentes fra EN CDN. Så du vil ikke se require() eller import i de umiddelbare eksemplene nedenfor. Mot slutten av denne opplæringen skjønt, vil vi introdusere Webpack Og Babel for GitHub guider. På det tidspunktet er DET ALT ES6!

React-Router

React er ikke et rammeverk, Det er et bibliotek. Derfor løser det ikke alle et programs behov. Det gjør en god jobb med å skape komponenter og gi et system for styring av staten, men å skape et mer komplekst SPA vil kreve en støttende cast. Den første Som vi skal se på Er React Router.

hvis du har brukt noen front-end router før, vil mange av disse konseptene være kjent. Men i motsetning til alle andre ruter jeg har brukt før, Bruker React Router JSX, som kanskje ser litt rart ut først.

som en primer, er dette hvordan det er å gjengi en enkelt komponent:

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

Slik blir komponenten Home gjengitt Med React Router:

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

Merk at <Router> og <Route> er to forskjellige ting. De er Teknisk Reagerer komponenter, men de faktisk ikke lage DOM selv. Selv om det kan se ut som <Router> selv blir gjengitt til 'root', definerer vi faktisk bare regler om hvordan søknaden vår fungerer. Fremover ser du dette konseptet ofte: komponenter eksisterer noen ganger ikke for å skape DOM selv, men å koordinere andre komponenter som gjør det.

i eksemplet definerer <Route> en regel der besøk på hjemmesiden / vil gjengi Home – komponenten i 'root'.

Flere Ruter

i forrige eksempel er enkeltruten veldig enkel. Det gir oss ikke mye verdi siden vi allerede hadde muligheten til å gjengi komponenten Home uten at ruteren var involvert.

React Router ‘ s power kommer inn når vi bruker flere ruter for å definere hvilken komponent som skal gjengis basert på hvilken bane som er aktiv:

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

Hver <Route> vil gjengi sin respektive komponent når banen samsvarer MED NETTADRESSEN. Bare en av disse tre komponentene vil bli gjengitt i 'root' til enhver tid. Med denne strategien monterer vi ruteren TIL DOM 'root' en gang, så bytter ruteren komponenter inn og ut med ruteendringer.

det er også verdt å merke seg at ruteren vil bytte ruter uten å gjøre forespørsler til serveren, så tenk at hver komponent kan være en helt ny side.

Gjenbrukbar Layout

Vi begynner å se den ydmyke begynnelsen av En Enkelt Side Søknad. Men det løser fortsatt ikke virkelige problemer. Jo, vi kunne bygge de tre komponentene for å være fulle HTML-sider,men hva med kodebruk? Sjansene er at disse tre komponentene deler felles eiendeler som en header og sidebar, så hvordan forhindrer VI HTML-repetisjon i hver komponent?

la oss tenke oss at vi skulle bygge en web app som lignet denne mockup:

en enkel nettside mockup.

når du begynner å tenke på hvordan denne mockupen kan brytes ned i gjenbrukbare seksjoner, kan du ende opp med denne ideen:

Hvordan du kan bryte opp den enkle web mockup i seksjoner.

Tenker i form av nestable komponenter og oppsett vil tillate oss å lage gjenbrukbare deler.

Plutselig lar kunstavdelingen deg vite at appen trenger en side for å søke widgets som ligner på siden for å søke brukere. Med Brukerliste og Widget Liste både krever samme «look» for deres søkeside, ideen om Å ha Søk Layout som en egen komponent gjør enda mer fornuftig nå:

Søk etter widgets nå, i stedet for brukere, men foreldreseksjonene forblir de samme.

Søkeoppsett kan være en overordnet mal for alle typer søkesider nå. Og mens noen sider kan trenge Søkeoppsett, kan andre direkte bruke Hovedoppsett uten det:

en layout avkoblet.

Dette er en vanlig strategi, og hvis du har brukt et templeringssystem, har du sannsynligvis gjort noe veldig likt. La oss nå jobbe MED HTML. For å starte, vil vi gjøre statisk HTML uten Å vurdere 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>

Husk at 'root' – elementet alltid vil være til stede siden det er det eneste elementet SOM den første HTML-Kroppen har før JavaScript starter. Ordet «root» er hensiktsmessig fordi hele React-applikasjonen vår vil montere på den. Men det er ikke noe «riktig navn» eller konvensjon til det du kaller det. Jeg har valgt «root», så vi fortsetter å bruke den gjennom eksemplene. Bare vær oppmerksom på at montering direkte på <body> – elementet er svært motløs.

etter å ha opprettet den statiske HTML, konvertere Den Til React komponenter:

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> ); }});

Ikke bli for distrahert mellom det jeg kaller «Layout» vs «Komponent». Alle Tre Av Disse Er React-komponenter. Jeg velger bare å ringe to av dem «Layouter» siden det er rollen de utfører.

vi vil til slutt bruke «nestede ruter» for å plassere UserList inne SearchLayout, deretter inne MainLayout. Men først, legg merke til at når UserList er plassert inne i sin forelder SearchLayout, vil foreldrene bruke this.props.children for å bestemme plasseringen. Alle komponenter har this.props.children som en prop, men det er først når komponenter er nestet at foreldrekomponenten får denne prop fylt automatisk ved React. For komponenter som ikke er overordnede komponenter, vil this.props.children være null.

Nestede Ruter

så Hvordan får vi disse komponentene til nest? Ruteren gjør det for oss når vi hekker ruter:

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

Komponenter vil bli nestet i henhold til hvordan ruteren reder sine ruter. Når brukeren besøker ruten /users, Vil React Router plassere komponenten UserList inne SearchLayout og deretter begge inne MainLayout. Sluttresultatet av å besøke /users vil være de tre nestede komponentene plassert inne 'root'.

Legg Merke til at vi Ikke har en regel for når brukeren besøker hjemmesiden banen (/) eller ønsker å søke widgets. De ble utelatt for enkelhet, men la oss sette dem inn med den nye ruteren:

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'));

du har sikkert lagt merke til nå AT JSX følger XML-regler i den forstand at komponenten Route enten kan skrives som en tag: <Route /> eller to: <Route>...</Route>. Dette gjelder for ALLE JSX inkludert tilpassede komponenter og normale DOM noder. For eksempel er <div /> gyldig JSX og vil konvertere til <div></div> når gjengitt.

for korthet, tenk deg WidgetListligner UserList.

siden <Route component={SearchLayout}> har to barnruter nå, kan brukeren besøke /users eller /widgets og den tilsvarende <Route> vil laste sine respektive komponenter inne i SearchLayout komponenten.

legg også merke til hvordan Home komponenten vil bli plassert direkte inne MainLayout uten SearchLayout å være involvert — på grunn av hvordan <Route>s er nestet. Du kan sikkert forestille deg at det er enkelt å omorganisere hvordan oppsett og komponenter er nestet ved å omorganisere rutene.

IndexRoutes

React Router er veldig uttrykksfulle og ofte er det mer enn en måte å gjøre det samme på. For eksempel kunne vi også ha skrevet ruteren ovenfor som dette:

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'));

Til tross for sin annerledes utseende, de begge fungerer på nøyaktig samme måte.

Valgfrie Ruteattributter

noen ganger vil <Route> ha et component – attributt uten path, som i SearchLayout – ruten ovenfra. Andre ganger kan det være nødvendig å ha en <Route> med en path og nei component. For å se hvorfor, la oss starte med dette eksemplet:

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

/product – delen av path er repeterende. Vi kan fjerne repetisjonen ved å pakke alle tre ruter i en ny <Route>:

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

Igjen, React Router viser sin uttrykksevne. Quiz: la du merke til problemet med begge løsningene? For øyeblikket har vi ingen regler for når brukeren besøker /product banen.

for å fikse dette kan vi legge til en IndexRoute:

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

Bruk <Link> ikke <a>

når du oppretter ankre for rutene dine, må du bruke <Link to=""> i stedet for <a href="">. Ikke bekymre deg, når Du bruker komponenten <Link>, Vil React Router til slutt gi deg et vanlig anker I DOM. Å bruke <Link> er nødvendig for React Router å gjøre noe av sin rutemagi.

La oss legge til noen lenke (ankre) til vår 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> ); }});

Attributter på <Link> komponenter sendes gjennom til ankeret de oppretter. Så DETTE JSX:

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

Vil bli DETTE I DOM:

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

hvis du trenger å opprette et anker for ikke-ruter-baner, for eksempel et eksternt nettsted, bruk vanlige ankerkoder som vanlig. For mer informasjon, se dokumentasjonen For IndexRoute og Link.

Aktive Lenker

en kul funksjon i komponenten <Link> er dens evne til å vite når den er aktiv:

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

hvis brukeren er på /users – banen, vil ruteren søke etter matchende ankre som ble laget med <Link>, og det vil bytte sin active – klasse. Se mer på denne funksjonen.

Nettleserhistorikk

for å unngå forvirring har jeg utelatt en viktig detalj til nå. <Router> trenger å vite hvilken historikksporingsstrategi som skal brukes. React Router docs anbefaler browserHistory som er implementert som følger:

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

i tidligere versjoner Av React Router var attributtet history ikke nødvendig, og standard var å bruke hashHistory. Som navnet antyder, brukte det et # hash-tegn i NETTADRESSEN for å administrere front-end SPA – stil ruting, som ligner på Hva du kan forvente fra En Ryggrad.js router.

Med hashHistory Vil Nettadresser se slik ut:

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

hva skjer med de stygge spørringsstrengene skjønt?

når browserHistory er implementert, ser banene mer organisk ut:

  • example.com
  • example.com/users
  • eksempel.com/widgets

Det er en advarsel om på serveren når browserHistory brukes på fronten. Hvis brukeren starter besøket på example.com og deretter navigerer til /users og /widgets, håndterer React Router dette scenariet som forventet. Men hvis brukeren starter besøket ved å skrive example.com/widgets direkte inn i nettleseren, eller hvis de oppdaterer på example.com/widgets, må nettleseren gjøre minst en forespørsel til serveren for /widgets. Hvis det ikke er en server-side router skjønt, vil dette levere en 404:

Forsiktig Med Nettadresser. Du trenger en server side router.

For å løse 404-problemet fra serveren anbefaler React Router en jokertegn-ruter på serversiden. Med denne strategien, uansett hvilken server-side rute kalles, serveren skal alltid tjene samme HTML-fil. Så hvis brukeren starter direkte på example.com/widgets, selv om den samme HTML-filen returneres, Er React Router smart nok til å laste inn riktig komponent.

brukeren vil ikke merke noe rart, men du kan ha bekymringer om alltid serverer samme HTML-fil. I kodeeksempler vil denne serien fortsette å bruke «wildcard router» – strategien, men det er opp til deg å håndtere serversiden din på måter som passer deg.

Kan React Router brukes på både server-side og klientside på en isomorf måte? Klart det kan, men det er langt utenfor rammen av denne opplæringen.

Viderekobling med browserHistory

browserHistory objektet er en singleton, slik at du kan inkludere det i noen av filene dine. Hvis du trenger å omdirigere brukeren manuelt i noen av koden din, kan du bruke den push – metoden for å gjøre det:

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

Rutetilpasning

React router håndterer rutetilpasning på samme måte som andre rutere:

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

denne ruten vil samsvare når brukeren besøker en sti som starter med users/ og har noen verdi etterpå. Det vil matche /users/1, /users/143, eller til og med /users/abc(som du må validere på egen hånd).

React Router vil passere verdien for :userId som en prop til UserProfile. Denne rekvisitter er tilgjengelig som this.props.params.userId inne UserProfile.

Router Demo

På dette punktet har vi nok kode til å vise en demo.

Se Pen React-Router Demo Av Brad Westfall (@bradwestfall)På CodePen.

hvis du klikket på noen ruter i eksemplet, kan du legge merke til at nettleserens tilbake-og fremoverknapper fungerer med ruteren. Dette er en av hovedgrunnene til at disse history strategiene eksisterer. Husk også at med hver rute du besøker, er det ingen forespørsler som blir gjort til serveren bortsett fra den aller første til å få den første HTML. Hvor kult er det?

ES6

I Vårt CodePen-eksempel er React, ReactDOM og ReactRouter globale variabler fra EN CDN. Inne i ReactRouter – objektet er alle slags ting vi trenger som Router og Route – komponentene. Så vi kunne bruke ReactRouter som dette:

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

Her må vi prefiks alle våre ruterkomponenter med deres overordnede objekt ReactRouter. Eller VI kunne bruke ES6S nye destruktureringssyntaks som dette:

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

Denne «trekker ut» deler av ReactRouter i normale variabler, slik at vi kan få tilgang til dem direkte.

fra og med nå vil eksemplene i denne serien bruke EN rekke ES6-syntakser, inkludert destrukturering, spredningsoperatør, import/eksport og kanskje andre. Det vil være en kort forklaring på hver ny syntaks som de vises, og GitHub repo som følger med denne serien har også mange ES6 forklaringer.

Bunting med webpack Og Babel

som nevnt tidligere, kommer denne serien med En GitHub repo slik at du kan eksperimentere med kode. Siden DET vil ligne makings av en real-world SPA, vil det bruke verktøy som webpack Og Babel.

  • webpack bunter flere JavaScript-filer i en fil for nettleseren.
  • Babel vil konvertere es6 (ES2015) kode TIL ES5, siden de fleste nettlesere ennå ikke forstår ALLE ES6. Som denne artikkelen aldre, nettlesere vil støtte ES6 Og Babel kan ikke være nødvendig.

hvis du ikke er så komfortabel med å bruke disse verktøyene ennå, ikke bekymre deg, eksempelkoden har alt oppsett allerede, slik at du kan fokusere På React. Men vær sikker på å gjennomgå eksempelkodens README.md fil for ytterligere arbeidsflyt dokumentasjon.

Vær Forsiktig Med Utdatert Syntaks

Søk På Google etter informasjon Om React Router kan lande Deg på en av de mange artiklene eller StackOverflow-sidene som ble skrevet da React Router var i sin pre-1.0-utgivelse. Mange funksjoner fra pre-1.0 utgivelsen er foreldet nå. Her er en kort liste:

  • <Route name="" /> er utdatert. Bruk <Route path="" /> i stedet.
  • <Route handler="" /> er utdatert. Bruk <Route component="" /> i stedet.
  • <NotFoundRoute /> er utdatert. Se Alternativ
  • <RouteHandler /> er utdatert.
  • willTransitionTo er utdatert. Se onEnter
  • willTransitionFrom er utdatert. Se onLeave
  • «Steder» kalles nå «historier».

Se hele listen for 1.0.0 og 2.0.0

Sammendrag

Det er fortsatt flere funksjoner I React Router som ikke ble vist, så husk å sjekke UT API-Dokumentene. Skaperne Av React Router har også laget en trinnvis veiledning For React Router og også kassa Denne React.js Conf Video om hvordan React Router ble opprettet.

Spesiell takk Til Lynn Fisher for kunstverket @lynnandtonic

Artikkelserie:

  1. React Router (Du er her !)
  2. Beholderkomponenter
  3. Redux

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert.