/users/manuel
auf, möchte ich dort sehr wahrscheinlich das Benutzerprofil des Users manuel
anzeigen.BrowserRouter
, Link
, Route
, Redirect
und Switch
. Darüber hinaus gibt es noch die imperative History API, die durch das history
-Package, einem dünnen Layer über der nativen Browserimplementierung, wodurch diese cross-browser fähig gemacht wird, sowie die Higher Order Component withRouter
, um für das Routing relevante Daten aus dem Router in eine Komponente hinein zu reichen.<Router></Router>
-Elements kann nun auf den Router Context zugreifen, darauf reagieren und ihn steuern. Verschiedene Routen legen wir durch die Verwendung der Route-Komponente an, die eine path
-Prop enthalten sollte (Ausnahme: 404 Fehler-Routen) und wahlweise eine render
-Prop oder eine component
-Prop enthält. Der Unterschied liegt hier darin, dass der Wert der render
-Prop eine Funktion sein muss, die ein valides React-Element zurückgibt (hier sei auch nochmal an das entsprechende Kapitel zu Render-Props erinnert), während die component
-Prop eine Komponente (kein Element!) erwartet.Example
-Komponente beim Aufruf der /example
URL zweimal gerendert werden, da die Route-Komponente lediglich überprüft, ob der Pfad der aktuellen URL mit dem in der path
-Prop angegebenen Wert übereinstimmt. Dies mag erst einmal verwunderlich klingen, lässt sich aber ganz logisch erklären./account
URL nicht nur die Account
-Komponente, sondern ebenfalls die Home
-Komponente. Dies passiert, weil /account
auch den Pfad /
beinhaltet, und somit werden beide Komponenten gerendert. Das ist durchaus so gewollt, so wäre es z.B. möglich einzelne Seitenbereiche unter einem bestimmten URL Präfix zu gliedern und dabei eine Komponente auf jeder dieser Routen rendern zu lassen./account/edit
, um das eigene Profil zu bearbeiten, /account/images
, um die eigenen Bilder anzusehen oder /account/settings
, um Änderungen an den eigenen Einstellungen vorzunehmen. Wir können nun eine generische Route in unsere Anwendung einfügen:AccountSidebar
-Komponente würde nun auf jeder Unterseite innerhalb des Account-Bereichs angezeigt, solange eben die URL mit /account
beginnt.path
und der URL bewusst einzuschränken, bietet uns React Router die exact
Prop auf der Route
-Komponente. Wird diese Boolean-Prop angegeben, wird eine Route nur noch dann gerendert, wenn ihre path
-Prop auch exakt mit der aktuellen URL übereinstimmt:path
-Prop, um den Eindruck einer „sprechenden“ Prop zu vermitteln: hier habe ich eine Route mit dem exact path. In unserem Beispiel mit der Account-Sidebar würde die Sidebar bei Verwendung der exact
-Prop nun nur noch dann gerendert, wenn die URL /account
entspricht, jedoch nicht mehr bei /account/edit
, /account/images
oder /account/settings
.exact
-Prop bezieht sich dabei immer nur auf eine einzelne Route und lässt andere Routen davon gänzlich unberührt. Haben wir eine Reihe von URLs, von denen in bestimmten Fällen mehrere Routen matchen können, wird das mitunter mühsam, jeder einzelnen dieser Routen eine weitere Prop hinzuzufügen. Hier hilft uns der nächste Import aus dem React Router Paket weiter: Switch
.Switch
-Komponente, die sich um eine Reihe von <Route />
-Elementen legt, sorgen wir dafür, dass jeweils immer nur die erste Route, deren path
mit der aktuellen URL übereinstimmt, gerendert wird. Oft ist es keine schlechte Idee, Routen grundsätzlich in einem Switch
-Element zu verpacken, außer man möchte eben explizit, dass mehrere Routen gerendert werden. Statt der Verwendung der exact
-Prop wie im obigen Beispiel, wäre auch die Verwendung der Switch
-Komponente möglich:/account
-URL würde nun gleich die erste Route zutreffen und alle folgenden Routen würden ignoriert, wir würden also nur die Account
-Komponente rendern. Dabei prüft die Switch
-Komponente auch stets nur ihre direkten Kind-Elemente auf ein Matching mit der URL. Enthält die Account
-Komponente wiederum eigene Routen, was problemlos möglich ist, sind diese von der Switch-Komponente unbeeindruckt und werden gerendert, wenn ihr path
mit der aktuellen URL übereinstimmt.path
-Prop aus, bedeutet dies, dass diese Route auf jede URL zutrifft. Nutzen wir sie also innerhalb eines Switch
-Elements als letzte Komponente, sagen wir dem React Router damit: Rendere diese Komponente immer dann, wenn keine andere Route zutrifft – und zwar nur dann!Switch
-Element auch noch eine exact
-Prop bei der /
-Route notwendig, da sonst diese immer zutreffen würde, wenn vorher keine andere der Routen auf die aktuelle URL zutrifft, da der Router eben so funktioniert, dass bspw. auch /existiert-nicht
unter der /
-Route gefunden werden würde. Mit der exact
-Prop auf der Home
-Route passiert eben genau dies nicht und stattdessen sehen wir unsere Error404
-Komponente die am Ende unseres Switch
-Blocks alle Aufrufe abfängt. Vergleichbar mit dem default
-Fall in einem switch
-Statement in JavaScript.:
)./products/asc
oder /products/desc
lautet.:userid
erlaubt sind, so kann ich dafür die Route definieren: /users/:userid(\d*)
oder /users/:userid([0-9]*)
und somit würde die URL /users/123
die UserProfile
-Komponente rendern, /users/abc
hingegen nicht.match
-Prop an die gerenderte Komponente.Route
-Komponente, um auf bestimmte Routen zu reagieren, bietet React Router auch noch eine Redirect
-Komponente. Diese enthält eine to
-Prop, mit der ein Ziel angegeben werden kann und sie ist dazu gedacht um deklarativ (d.h. im JSX) entscheiden zu können, wohin ein Benutzer in bestimmten Situationen umgeleitet wird. Wann immer eine Redirect
-Komponente mit lediglich einer to
-Prop gerendert wird, wird eine entsprechende Weiterleitung auf die in der to
-Prop angegebene URL ausgeführt.Redirect
-Komponente ist bspw. die Umleitung auf eine Login-Seite für eingeloggte Benutzer, wenn dieser noch nicht eingeloggt ist:render
-Prop der Route
-Komponente, um in einer Funktion abzufragen ob ein Benutzer eingeloggt ist (mittels isLoggedIn
) und zeigen auf der /
URL entweder eine Dashboard-Komponente, oder rendern eben einen Redirect zu /login
, der den Benutzer dann eben auf eine Login-Seite weiterleiten würde.Redirect
-Komponente innerhalb eines <Switch/>
-Elements. Hier verhält sie sich so wie die Route
-Komponente und greift nur dann, wenn nicht bereits eine andere Route oder ein anderer Redirect mit der aktuellen URL übereingestimmt hat.Redirect
-Komponente in einem <Switch/>
-Element benutzt (und nur dann!) kann sie auch eine from
-Prop bekommen. Diese entspricht der path
-Prop bei der Route
-Komponente, sorgt also dafür, dass der Redirect nur durchgeführt wird, wenn die aktuelle URL dem Wert der from
-Prop entspricht:Redirect
-Komponente verhält sich dabei was das Matching der URLs angeht genau wie die Route
-Komponente. Sie unterstützt ebenfalls die exact
-Prop, um ein exaktes Matching zu erzwingen und sie unterstützt auch die Umleitung an andere Routen mit Parameter:/old
(erstes Beispiel) bzw. /users/123
(zweites Beispiel) wird der Benutzer dann auf die als to
-Prop angegebene URL umgeleitet.component
-Prop einer Route
-Komponente angegeben wurde, bekommt automatisch drei für das Routing relevante Props übergeben:match
location
history
this.props
in Klassen-Komponenten oder props
in Function Components zugegriffen werden:/users/123
ein Resultat, das diesem entspricht (gekürzt):match
-Eigenschaft. Diese enthält bei einer zutreffenden URL in match.params
die Parameter, die wir im path
definiert haben mitsamt ihrer Werte. In diesem Fall also match.params.userid
mit dem Wert 123
.123
zu besorgen und die Profilansicht dieses Benutzers darzustellen.match
-Eigenschaft immer existiert und diese auch immer eine params
-Eigenschaft hat, die entweder die Parameter enthält (falls vorhanden) oder aber ein leeres Objekt ist. Es ist daher sicher, auf props.match.params
zuzugreifen, ohne befürchten zu müssen, dass eine dieser Eigenschaften undefined
ist und somit einen Fehler wirft.render
-Prop auf der Route
-Komponente bekommt alle Props des Routers übergeben:<a href="...">...</a>
, keine Frage. Allerdings lösen wir damit einen komplett neuen „harten“ Seitenaufruf im Browser aus, verlassen die aktuelle Seite komplett und rufen die neue Seite komplett neu auf.Link
-Komponente mit. Diese wird wie alle anderen Komponenten aus dem react-router-dom
-Paket importiert und besitzt eine to
-Prop, die man grob mit dem href
-Attribut bei HTML a
-Elementen vergleichen kann:<a href />
, jedoch werden Klicks auf diese Links abgefangen und an eine interne Funktion weitergeleitet, die sich dann darum kümmert, neue Seiteninhalte auf Basis der neuen URL darzustellen, ohne dabei einen vollständigen Pageload auszulösen.to
-Prop kann ein Link
auch eine innerRef
besitzen, die eine über createRef()
oder useRef()
erzeugte Ref erhalten kann sowie eine replace
-Prop, mit der wir festlegen können, dass wir die aktuelle URL in der Browser-History ersetzen wollen statt einen neuen History-Eintrag zu erzeugen. Beim Klick auf den Zurück-Button im Browser kann dann nicht mehr auf die vorherige Route zurückgesprungen werden.<Link />
-Element übergeben werden, werden an das erzeugte a
-Element weitergereicht. So würde <Link to="/" title="Homepage">Home</Link>
in der Ausgabe entsprechend das folgende Markup erzeugen: <a href="/" title="Homepage">Home</a>
.Link
-Elements stellt der NavLink
dar. Neben den Props, die auch die Link
-Komponente erhalten kann, kennt der NavLink
darüber hinaus seinen aktuellen Zustand in dem Sinne, dass er weiß, ob er gerade auf die aktuelle Seite verlinkt. Ist dies der Fall, können ihm mittels activeClassName
und activeStyle
ein alternatives Erscheinungsbild verpasst werden.active
erhalten. Befinden wir uns bspw. auf der /account
URL, wäre das Markup dementsprechend:NavLink
-Element enthalten kann sind exact
und strict
, analog zu den entsprechenden Props bei der Route
-Komponente, sowie isActive
. Letztere erwartet eine Funktion, die entweder true
(aktive Seite entspricht dem NavLink
) oder false
(aktive Seite entspricht ihm nicht) zurückgibt. Die Funktion selbst bekommt vom Router als erstes Argument das match
-Objekt und als zweites Argument das location
-Objekt übergeben. Die Funktion kann anhand dieser Information nun ermitteln ob sie den jeweiligen NavLink
als aktiv markiert oder nicht.Route
-Elemente auf verschiedene URLs mit dem Rendering entsprechender Komponenten reagieren können und wissen, wie wir auf einen harten Pageload durch die Verwendung des <Link />
-Elements verzichten. Doch in manchen Fällen ist es notwendig, einen Wechsel der URL programmatisch zu forcieren. Etwa, um den Benutzer auf eine andere Seite weiterzuleiten nachdem ein asynchroner Request erfolgreich war.history
-Eigenschaft, die der Router allen als Route verwendeten Komponenten in den Props
übergibt:push()
sowie replace()
. Mittels props.history.push('/ziel')
können wir die URL im Browser auf /ziel
ändern, sowie ein Rerendering auslösen. Dabei wird, wie auch bei der Verwendung der Link
-Komponente ein neuer Eintrag in der Browser-History erzeugt. Möchten wir hingegen keinen neuen Eintrag in der Browser-History erzeugen, können wir stattdessen die Funktion props.history.replace('/ziel')
verwenden.props.history.go()
ermöglicht es uns, in der Browser-History programmatisch vor- und zurückzublättern. Die Funktion erwartet dabei einen Integer als Parameter, der angibt, um wie viele Schritte in der History geblättert werden soll. Negative Werte blättern dabei zurück, während positive Werte vorwärts blättern. Die beiden Funktionen goBack()
und goForward()
sind dabei Shortcuts, die jeweils einen Schritt in der History zurück- bzw. vorblättern. Sie entsprechen also go(-1)
bzw. go(1)
.action
Eigenschaft verrät uns, durch welche Aktion ein Benutzer auf der aktuellen Route gelandet ist. Sie ist entweder POP
, PUSH
oder REPLACE
, wobei POP
sowohl bedeuten kann, dass es sich um den initialen Seitenaufruf handelt oder der Benutzer den Zurück-Button im Browser gedrückt hat, PUSH
bedeutet, dass die history.push()
Funktion aufgerufen wurde, was auch beim Klick auf einen <Link />
der Fall ist. Ist der Wert der action
-Eigenschaft REPLACE
- ihr könnt es euch denken - wurde history.replace()
aufgerufen oder ein <Link />
-Element geklickt, dass eine replace
-Prop besitzt.component
-Prop innerhalb eines <Router />
-Elements verwendet wird, bekommt die Router Props (history
, location
, match
) automatisch von diesem übergeben. Doch manchmal möchten wir auch in Komponenten, die nicht als direkte Route verwendet werden, auf Router-Funktionalität zugreifen. Etwa, weil wir auf eine andere Seite weiterleiten möchten und dafür history.push()
verwenden möchten.withRouter
Higher Order Component bereit. Komponenten, die nicht direkt als Router-Komponente eingesetzt werden, bekommen dann ebenfalls die drei Props des Routers übergeben:PureComponent
implementiert oder von einem React.memo()
optimiert werden und dementsprechend ein Rerendering unterbinden, wenn sich weder die eigenen Props noch der State der jeweiligen Komponente ändern. Da die meisten Router-Komponenten wie bspw. NavLink
auf die Daten des Routers durch den React Context zugreifen, würde eine solche Komponente dann unter Umständen keine Kenntnis darüber erlangen, dass ein Kind-Element neu gerendert werden muss.withRouter()
HOC zu verpacken, die dann bei jeder Änderung im Routing die neuen Props mit der neuen Location an die jeweilige Komponente übergibt und in dieser somit ein Rerendering verursacht. Dies ist bspw. der Fall bei der Verwendung mit der State Management Library Redux. Wird eine Komponente über die connect()
-Funktion in Redux mit dem Redux-Store verbunden, unterbindet diese Komponente das Rerendering von routerspezifischen Teilen, außer es ändert sich gleichzeitig etwas im Store.withRouter()
Aufruf zu wrappen:withRouter()
-HOC zu verwenden, wenn diese nicht direkt als Komponente eines <Route />
-Elements verwendet werden (also etwa <Route component={MyComponent} />
).location
-Objekt, die history
-Instanz, die Route-Parameter oder das match
-Objekt erlauben. Die Hooks heißen entsprechend useLocation
, useHistory
, useParams
und useRouteMatch
. Voraussetzung für die Verwendung der Hooks ist, dass sich die Komponente in der der Hook verwendet werden soll innerhalb eines <Router>
Baumes befindet. Das muss aber nicht auf oberster Ebene und direkt unterhalb des Router
-Elements sein. Die Hooks greifen jeweils auf den Router-Context zu und können sich so an beliebiger Stelle in einer Anwendung befinden.useLocation
. Diesen importieren wir zuerst als benannten Import aus dem react-router-dom
-Paket. Anschließend können wir auf die Location-Daten zugreifen indem wir den Rückgabewert des Hooks verwenden:ShowLocationInfo
-Komponente bei ihrer Verwendung etwa eine Ausgabe wie die folgende verursachen:useHistory()
-Hook erlaubt uns den Zugriff auf die verwendete history
-Instanz des React Routers. Dieses bietet uns die Möglichkeit, die URL über die bereits beschriebenen push()
und replace()
Methoden zu verändern (und dabei ein Rerendering der Anwendung auszulösen) oder über go()
, goBack()
, goForward()
durch die Browser-History zu navigieren.match.params
etwas versteckt haben. Definiere ich eine Route mit Platzhaltern, also etwa /users/:userid
und rufe dann eine URL auf wie /users/123
enthält das params-Objekt ein key/value Paar in der Form { "userid": "123" }
./users/:userid
) und dem Aufruf etwa von /users/123
folgende Ausgabe erzeugen:useRouteMatch()
, gibt dem Entwickler Zugriff auf das komplette match
-Objekt zu einer Route, bestehend aus den params
, der url
, dem path
und isExact
, also der Information, ob die komplette URL mit dem path
der Route übereinstimmt.match
-Objekt zu dieser Route zurück. Wird kein Pfad übergeben wird der Pfad der aktuellen Route verwendet. Bleiben wir beim obigen Beispiel mit einem Pfad /users/:userid
, ergibt die Route <Route path="/users/:userid">
beim Aufruf der URL /users/123
und dem Aufruf des Hooks ohne Parameter etwa folgendes Match-Objekt:null
aus der Funktion zurückgegeben:/users/:userid
also null
zurückgeben.