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:
- serie Code
- React-Router
- meerdere Routes
- Herbruikbare lay-out
- geneste Routes
- IndexRoutes
- optionele Routekenmerken
- gebruik <Link> niet <a>
- actieve koppelingen
- Browsergeschiedenis
- Redirect with browserHistory
- Routeafstemming
- Router Demo
- ES6
- gebundeld met webpack en Babel
- wees voorzichtig met verouderde syntaxis
- samenvatting
- Article Series:
serie artikelen:
- React Router (u bent hier!)
- Containercomponenten
- 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:
wanneer u begint na te denken over hoe deze mockup kan worden opgesplitst in herbruikbare secties, zou u kunnen eindigen met dit idee:
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:
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:
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 component
te 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:
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:
- React Router (u bent hier!)
- Containercomponenten
- Redux