Leveling met React: React Router

deze tutorial is de eerste van een driedelige serie over React door Brad Westfall. Toen Brad gooide me dit, hij wees erop dat er een goede hoeveelheid tutorials op aan de slag in React, maar niet zo veel over waar te gaan vanaf daar. Als je gloednieuw bent om te reageren, raad ik aan om deze intro video te bekijken. Deze serie gaat verder waar de basis ophoudt.

serie artikelen:

  1. React Router (u bent hier!)
  2. Containercomponenten
  3. Redux

Waarschuwing! Dit artikel is geschreven pre-React Router 4, die is uitgegroeid tot een meer standaard keuze voor routing in React. Er is een nieuw artikel over React Router 4 Hier moet u zeker lezen.

toen ik voor het eerst leerde, vond ik veel beginner gidsen (dat wil zeggen 1, 2, 3, 4) die lieten zien hoe afzonderlijke componenten te maken en ze te renderen naar de DOM. Ze deden een prima werk van het onderwijzen van de basics zoals JSX en rekwisieten, maar ik worstelde met het uitzoeken hoe React werkt in het grotere plaatje – als een real-world Single Page applicatie (SPA). Aangezien deze serie veel materiaal omvat, zal het niet de absolute beginnersconcepten dekken. In plaats daarvan begint het met de aanname dat je al begrijpt hoe je ten minste één component kunt maken en renderen.

voor wat het waard is, hier zijn enkele andere grote gidsen die gericht zijn op beginners:

  • reageer.js en hoe past het bij al het andere?
  • Herdenken (Industrie) Beste Praktijken
  • React.js introductie voor mensen die net genoeg jQuery kennen om door

serie Code

deze serie komt ook met enige code om mee te spelen op GitHub. Gedurende de serie, zullen we het bouwen van een basic SPA gericht op gebruikers en widgets.

om de zaken eenvoudig en kort te houden, zullen de voorbeelden in deze serie beginnen met de veronderstelling dat React en React Router worden opgehaald uit een CDN. U ziet dus niet require() of import in de directe voorbeelden hieronder. Tegen het einde van deze tutorial zullen we echter Webpack en Babel introduceren voor de GitHub gidsen. Op dat moment is het allemaal ES6!

React-Router

React is geen framework, het is een bibliotheek. Daarom lost het niet alle behoeften van een toepassing op. Het doet een geweldige job bij het creëren van componenten en het verstrekken van een systeem voor het beheren van de staat, maar het creëren van een meer complexe SPA zal een ondersteunende cast vereisen. De eerste die we zullen kijken naar is React Router.

als u eerder een front-end router hebt gebruikt, zullen veel van deze concepten bekend zijn. Maar in tegenstelling tot elke andere router die ik eerder heb gebruikt, React Router maakt gebruik van JSX, die misschien een beetje vreemd op het eerste.

als een primer is dit hoe het is om een enkel component te renderen:

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

hier is hoe de Home component zou worden gerenderd met React Router:

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

merk op dat <Router> en <Route> twee verschillende dingen zijn. Het zijn technisch reactieve componenten,maar ze maken zelf geen DOM. Hoewel het eruit kan zien alsof de <Router> zelf wordt gerenderd naar de 'root', zijn we eigenlijk gewoon regels aan het definiëren over hoe onze applicatie werkt. In de toekomst zie je dit concept vaak: componenten bestaan soms niet om DOM zelf te maken, maar om andere componenten te coördineren die dat wel doen.

in het voorbeeld definieert de <Route> een regel waarbij het bezoeken van de homepage / de Home component weergeeft in de 'root'.

meerdere Routes

in het vorige voorbeeld is de enkele route zeer eenvoudig. Het geeft ons niet veel waarde omdat we al de mogelijkheid hadden om het Home component te renderen zonder dat de router erbij betrokken was.

de kracht van de React Router komt binnen wanneer we meerdere routes gebruiken om te bepalen welke component moet renderen op basis van welk pad momenteel actief is:

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

elke <Route> zal zijn respectievelijke component weergeven wanneer zijn pad overeenkomt met de URL. Slechts één van deze drie componenten zal op een gegeven moment in de 'root' worden weergegeven. Met deze strategie mounten we de router eenmaal naar de DOM 'root', waarna de router componenten in en uit wisselt met routewijzigingen.

het is ook vermeldenswaard dat de router van route zal wisselen zonder verzoeken naar de server te doen, dus stel je voor dat elk onderdeel een hele nieuwe pagina kan zijn.

Herbruikbare lay-out

we beginnen het bescheiden begin van een toepassing op één pagina te zien. Het lost echter nog steeds geen echte problemen op. Zeker, we zouden de drie componenten kunnen bouwen om volledige HTML-pagina ‘ s te zijn, maar hoe zit het met code hergebruik? De kans is groot dat deze drie componenten gemeenschappelijke activa delen zoals een header en zijbalk, dus hoe voorkomen we HTML herhaling in elk onderdeel?

stel je voor dat we een web-app aan het bouwen waren die leek op deze mockup:

een eenvoudige website mockup.

wanneer u begint na te denken over hoe deze mockup kan worden opgesplitst in herbruikbare secties, zou u kunnen eindigen met dit idee:

hoe je de eenvoudige web mockup zou kunnen splitsen in secties.

door te denken in termen van Nestbare componenten en lay-outs kunnen we herbruikbare onderdelen maken.

plotseling laat de afdeling Kunst u weten dat de app een pagina nodig heeft voor het zoeken naar widgets die lijkt op de pagina voor het zoeken van gebruikers. Met User List en Widget List beide die dezelfde “look” voor hun zoekpagina, het idee om te zoeken lay-out als een aparte component is nu nog zinvoller:

zoeken naar widgets nu, in plaats van gebruikers, maar de bovenliggende secties blijven hetzelfde.

Zoekopmaak kan nu een bovenliggende sjabloon zijn voor alle soorten zoekpagina ‘ s. En terwijl sommige pagina ‘ s zoeklay-out nodig hebben, kunnen anderen direct Hoofdlay-Out gebruiken zonder:

een lay-out ontkoppeld.

dit is een veelgebruikte strategie en als je een templating systeem hebt gebruikt, heb je waarschijnlijk iets dergelijks gedaan. Laten we nu aan de HTML werken. Om te beginnen zullen we statische HTML doen zonder JavaScript te overwegen:

<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>

onthoud dat het 'root' element altijd aanwezig zal zijn, omdat het het enige element is dat de oorspronkelijke HTML Body heeft voordat JavaScript start. Het woord “root” is toepasselijk omdat onze hele React applicatie er aan gekoppeld zal worden. Maar er is geen “juiste naam” of conventie bij hoe je het noemt. Ik heb gekozen voor “root”, dus we blijven het gebruiken in de voorbeelden. Pas op dat het direct aankoppelen op het <body> – element sterk wordt afgeraden.

na het maken van de statische HTML, converteer het naar react componenten:

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

raak niet te afgeleid tussen wat ik noem” lay-out ” vs “Component”. Alle drie zijn React componenten. Ik kies ervoor om twee van hen “lay-outs” te noemen omdat dat de rol is die ze uitvoeren.

we zullen uiteindelijk “geneste routes” gebruiken om UserList binnen SearchLayout te plaatsen, daarna binnen MainLayout. Maar merk eerst op dat wanneer UserList in zijn ouder SearchLayout wordt geplaatst, de ouder this.props.children zal gebruiken om zijn locatie te bepalen. Alle componenten hebben this.props.children als een prop, maar het is alleen wanneer componenten worden genest dat de ouder component deze prop automatisch wordt gevuld door React. Voor componenten die geen oudercomponenten zijn, is this.props.children null.

geneste Routes

dus hoe krijgen we deze componenten om te nestelen? De router doet het voor ons als we nestroutes:

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

componenten zullen worden genest in overeenstemming met hoe de router zijn routes nestelt. Wanneer de gebruiker de /users route bezoekt, plaatst de React Router het UserList component in SearchLayout en vervolgens beide in MainLayout. Het eindresultaat van een bezoek aan /users zijn de drie geneste componenten die binnen 'root'worden geplaatst.

merk op dat we geen regel hebben voor wanneer de gebruiker het pad van de homepage (/) bezoekt of widgets wil zoeken. Die werden weggelaten voor de eenvoud, maar laten we ze in te zetten met de nieuwe 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'));

u hebt waarschijnlijk al gemerkt dat JSX XML-regels volgt in de zin dat het Route – component kan worden geschreven als één tag: <Route /> of twee: <Route>...</Route>. Dit geldt voor alle JSX inclusief uw aangepaste componenten en normale DOM nodes. Bijvoorbeeld, <div /> is geldig JSX en zal converteren naar <div></div> wanneer gerenderd.

om kort te zijn, stel je voor dat WidgetList lijkt op de UserList.

omdat <Route component={SearchLayout}> nu twee onderliggende routes heeft, kan de gebruiker /users of /widgets bezoeken en de corresponderende <Route> zal zijn respectievelijke componenten laden binnen het SearchLayout component.

merk ook op hoe de Home component direct binnen MainLayout zal worden geplaatst zonder dat SearchLayout hierbij betrokken is-vanwege hoe de <Route>s worden genest. Je kunt je waarschijnlijk voorstellen dat het gemakkelijk is om de lay-outs en componenten te herschikken door de routes te herschikken.

IndexRoutes

React Router is zeer expressief en vaak is er meer dan één manier om hetzelfde te doen. We hadden bijvoorbeeld ook de bovenstaande router als volgt kunnen schrijven:

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

ondanks het andere uiterlijk werken ze allebei op exact dezelfde manier.

optionele Routekenmerken

soms zal <Route> een component attribuut hebben zonder path, zoals in de SearchLayout route van bovenaf. Andere keren kan het nodig zijn om een <Route> met een path en geen componentte hebben. Om te zien waarom, laten we beginnen met dit voorbeeld:

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

het /product deel van de path is repetitief. We kunnen de herhaling verwijderen door alle drie de routes in een nieuwe <Route>:

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

nogmaals, React Router toont zijn expressiviteit. Quiz: heb je het probleem met beide oplossingen opgemerkt? Op dit moment hebben we geen regels voor wanneer de gebruiker het /product pad bezoekt.

om dit op te lossen, kunnen we een IndexRoute:

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

gebruik <Link> niet <a>

wanneer u ankers maakt voor uw routes, moet u <Link to=""> gebruiken in plaats van <a href="">. Maak je echter geen zorgen, wanneer je de <Link> component gebruikt, zal React Router je uiteindelijk een gewoon anker in de DOM geven. Het gebruik van <Link> is echter noodzakelijk voor de React Router om een deel van zijn routeringsmagie uit te voeren.

laten we wat link (ankers) toevoegen aan onze 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> ); }});

attributen op <Link> componenten zullen worden doorgegeven aan het anker dat ze maken. Dus deze JSX:

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

zal dit worden in DOM:

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

als u een anker moet maken voor niet-routerpaden, zoals een externe website, gebruik dan normale anker tags zoals gewoonlijk. Voor meer informatie, zie de documentatie voor IndexRoute en Link.

actieve koppelingen

een cool kenmerk van het <Link> component is de mogelijkheid om te weten wanneer het actief is:

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

als de gebruiker zich op het /users pad bevindt, zal de router zoeken naar overeenkomende ankers die gemaakt zijn met <Link> en het zal hun active klasse omschakelen. Bekijk meer over deze functie.

Browsergeschiedenis

om verwarring te voorkomen, heb ik tot nu toe een belangrijk detail weggelaten. <Router> moet weten welke strategie voor het volgen van de geschiedenis moet worden gebruikt. React Router docs raden browserHistory die als volgt is geïmplementeerd:

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

In eerdere versies van React Router was het history attribuut niet vereist en was het standaard het gebruik van hashHistory. Zoals de naam al doet vermoeden, gebruikte het een # hash teken in de URL om front-end SPA-stijl routing te beheren, vergelijkbaar met wat je zou verwachten van een Backbone.js router.

met hashHistory zullen URL ‘ s er zo uitzien:

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

Wat is er met die lelijke query strings?

wanneer browserHistory is geïmplementeerd, lijken de paden meer organisch:

  • example.com
  • example.com/users
  • voorbeeld.com / widgets

er is echter een voorbehoud op de server wanneer browserHistory wordt gebruikt op de front-end. Als de gebruiker zijn bezoek start op example.com en vervolgens navigeert naar /users en /widgets, behandelt de React Router dit scenario zoals verwacht. Echter, als de gebruiker zijn bezoek begint door example.com/widgets rechtstreeks in de browser te typen, of als hij zich ververst op example.com/widgets, dan moet de browser ten minste één verzoek aan de server doen voor /widgets. Als er echter geen server-side router is, levert dit een 404:

voorzichtig met URL ‘ s. Je hebt een server side router nodig.

om het 404-probleem van de server op te lossen, adviseert React Router een jokertekens router aan de serverzijde. Met deze strategie, ongeacht welke server-side route wordt genoemd, moet de server altijd dezelfde HTML-bestand te dienen. Als de gebruiker dan direct begint op example.com/widgets, ook al wordt hetzelfde HTML-bestand geretourneerd, is React Router slim genoeg om de juiste component te laden.

de gebruiker zal niets raars opmerken, maar u kunt zich zorgen maken over het altijd aanbieden van hetzelfde HTML-bestand. In code voorbeelden, zal deze serie de “wildcard router” strategie blijven gebruiken, maar het is aan jou om je server-side routing af te handelen op manieren die jij nodig acht.

kan React Router op zowel server-zijde als client-zijde op een isomorfe manier worden gebruikt? Natuurlijk kan het, maar dat is ver buiten het bereik van deze tutorial.

Redirect with browserHistory

het browserHistory object is een singleton, zodat u het in elk van uw bestanden kunt opnemen. Als u de gebruiker handmatig moet omleiden in een van uw code, kunt u de push methode gebruiken om dit te doen:

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

Routeafstemming

Routeafstemming verloopt op dezelfde manier als bij andere routers:

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

deze route zal overeenkomen wanneer de gebruiker een pad bezoekt dat begint met users/ en daarna enige waarde heeft. Het komt overeen met /users/1, /users/143, of zelfs /users/abc (die u zelf moet valideren).

React Router zal de waarde voor :userId als prop doorgeven aan de UserProfile. Deze props wordt benaderd als this.props.params.userId binnen UserProfile.

Router Demo

op dit moment hebben we genoeg code om een demo te tonen.

zie de Pen React-Router Demo van Brad Westfall (@bradwestfall) op CodePen.

als u op een paar routes in het voorbeeld klikte, zou u kunnen merken dat de knoppen terug en vooruit van de browser werken met de router. Dit is een van de belangrijkste redenen waarom deze history strategieën bestaan. Houd er ook rekening mee dat bij elke route die u bezoekt, er geen verzoeken worden gedaan aan de server, behalve de allereerste om de initiële HTML te krijgen. Hoe cool is dat?

ES6

in ons CodePen-voorbeeld zijn React, ReactDOM en ReactRouter globale variabelen van een CDN. In het ReactRouter object zitten allerlei dingen die we nodig hebben, zoals de Router en Route componenten. Dus we kunnen ReactRouter als volgt gebruiken:

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

hier moeten we al onze routercomponenten prefixen met hun bovenliggende object ReactRouter. Of we kunnen ES6 ’s nieuwe destructieve syntaxis gebruiken zoals deze:

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

dit “extraheert” delen van ReactRouter in normale variabelen zodat we ze direct kunnen benaderen.

vanaf nu zullen de voorbeelden in deze serie een verscheidenheid aan ES6-syntaxen gebruiken, waaronder destructuring, de spread operator, import/export, en misschien anderen. Er zal een korte uitleg zijn van elke nieuwe syntaxis zoals ze verschijnen en de GitHub repo die bij deze serie wordt geleverd heeft ook veel ES6 uitleg.

gebundeld met webpack en Babel

zoals eerder vermeld, wordt deze serie geleverd met een GitHub repo zodat u kunt experimenteren met code. Omdat het zal lijken op de ingrediënten van een real-world SPA, het zal gebruik maken van tools zoals webpack en Babel.

  • webpack bundelt meerdere JavaScript-bestanden in één bestand voor de browser.
  • Babel zal ES6 (ES2015) code converteren naar ES5, omdat de meeste browsers nog niet alles van ES6 begrijpen. Aangezien dit artikel ouder wordt, zullen browsers ES6 ondersteunen en is Babel mogelijk niet nodig.

als u nog niet te comfortabel bent met het gebruik van deze tools, maak u geen zorgen, de voorbeeldcode heeft alles al ingesteld, zodat u zich kunt concentreren op reageren. Maar zorg ervoor dat u de voorbeeldcode ‘ s README.md bestand voor extra workflow documentatie.

wees voorzichtig met verouderde syntaxis

door Google te zoeken naar informatie over de React Router kunt u terecht op een van de vele artikelen of StackOverflow pagina ‘ s die werden geschreven toen de React Router in de pre-1.0 release was. Veel functies van de pre-1.0 release zijn nu verouderd. Hier is een korte lijst:

  • <Route name="" /> is verouderd. Gebruik <Route path="" /> in plaats daarvan.
  • <Route handler="" /> is verouderd. Gebruik in plaats daarvan <Route component="" />.
  • <NotFoundRoute /> is verouderd. Zie alternatief
  • <RouteHandler /> is verouderd.
  • willTransitionTo is verouderd. Zie onEnter
  • willTransitionFrom is verouderd. Zie onLeave
  • ” locaties “worden nu”geschiedenissen” genoemd.

zie de volledige lijst voor 1.0.0 en 2.0.0

samenvatting

er zijn nog meer functies in React Router die niet werden getoond, dus zorg ervoor dat u de API Docs bekijkt. De makers van React Router hebben ook een stap-voor-stap handleiding voor React Router en ook check-out deze React.js Conf Video over hoe React Router is gemaakt.

speciale dank aan Lynn Fisher voor het artwork @lynnandtonic

Article Series:

  1. React Router (u bent hier!)
  2. Containercomponenten
  3. Redux

Geef een antwoord

Het e-mailadres wordt niet gepubliceerd.