print.html 150 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040
  1. <!DOCTYPE HTML>
  2. <html lang="en" class="sidebar-visible no-js light">
  3. <head>
  4. <!-- Book generated using mdBook -->
  5. <meta charset="UTF-8">
  6. <title>Dioxus Router</title>
  7. <meta name="robots" content="noindex" />
  8. <!-- Custom HTML head -->
  9. <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
  10. <meta name="description" content="">
  11. <meta name="viewport" content="width=device-width, initial-scale=1">
  12. <meta name="theme-color" content="#ffffff" />
  13. <link rel="icon" href="favicon.svg">
  14. <link rel="shortcut icon" href="favicon.png">
  15. <link rel="stylesheet" href="css/variables.css">
  16. <link rel="stylesheet" href="css/general.css">
  17. <link rel="stylesheet" href="css/chrome.css">
  18. <link rel="stylesheet" href="css/print.css" media="print">
  19. <!-- Fonts -->
  20. <link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
  21. <link rel="stylesheet" href="fonts/fonts.css">
  22. <!-- Highlight.js Stylesheets -->
  23. <link rel="stylesheet" href="highlight.css">
  24. <link rel="stylesheet" href="tomorrow-night.css">
  25. <link rel="stylesheet" href="ayu-highlight.css">
  26. <!-- Custom theme stylesheets -->
  27. </head>
  28. <body>
  29. <!-- Provide site root to javascript -->
  30. <script type="text/javascript">
  31. var path_to_root = "";
  32. var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
  33. </script>
  34. <!-- Work around some values being stored in localStorage wrapped in quotes -->
  35. <script type="text/javascript">
  36. try {
  37. var theme = localStorage.getItem('mdbook-theme');
  38. var sidebar = localStorage.getItem('mdbook-sidebar');
  39. if (theme.startsWith('"') && theme.endsWith('"')) {
  40. localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
  41. }
  42. if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
  43. localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
  44. }
  45. } catch (e) { }
  46. </script>
  47. <!-- Set the theme before any content is loaded, prevents flash -->
  48. <script type="text/javascript">
  49. var theme;
  50. try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
  51. if (theme === null || theme === undefined) { theme = default_theme; }
  52. var html = document.querySelector('html');
  53. html.classList.remove('no-js')
  54. html.classList.remove('light')
  55. html.classList.add(theme);
  56. html.classList.add('js');
  57. </script>
  58. <!-- Hide / unhide sidebar before it is displayed -->
  59. <script type="text/javascript">
  60. var html = document.querySelector('html');
  61. var sidebar = 'hidden';
  62. if (document.body.clientWidth >= 1080) {
  63. try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
  64. sidebar = sidebar || 'visible';
  65. }
  66. html.classList.remove('sidebar-visible');
  67. html.classList.add("sidebar-" + sidebar);
  68. </script>
  69. <nav id="sidebar" class="sidebar" aria-label="Table of contents">
  70. <div class="sidebar-scrollbox">
  71. <ol class="chapter"><li class="chapter-item expanded affix "><a href="index.html">Introduction</a></li><li class="chapter-item expanded affix "><li class="part-title">Features</li><li class="chapter-item expanded "><a href="features/index.html"><strong aria-hidden="true">1.</strong> Adding the Router to Your Application</a></li><li class="chapter-item expanded "><a href="features/routes/index.html"><strong aria-hidden="true">2.</strong> Defining Routes</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="features/routes/nested.html"><strong aria-hidden="true">2.1.</strong> Nested Routes</a></li><li class="chapter-item expanded "><a href="features/routes/catch_all.html"><strong aria-hidden="true">2.2.</strong> Catch All Routes</a></li><li class="chapter-item expanded "><a href="features/routes/matching.html"><strong aria-hidden="true">2.3.</strong> Matching Routes</a></li><li class="chapter-item expanded "><a href="features/routes/fallback.html"><strong aria-hidden="true">2.4.</strong> Fallback Routes (404 page)</a></li><li class="chapter-item expanded "><a href="features/routes/multiple-and-redirect.html"><strong aria-hidden="true">2.5.</strong> Multiple Components &amp; Redirects</a></li></ol></li><li class="chapter-item expanded "><a href="features/outlets.html"><strong aria-hidden="true">3.</strong> Outlets</a></li><li class="chapter-item expanded "><a href="features/navigation/index.html"><strong aria-hidden="true">4.</strong> Links &amp; Navigation</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="features/navigation/name.html"><strong aria-hidden="true">4.1.</strong> Named Navigation</a></li><li class="chapter-item expanded "><a href="features/navigation/external.html"><strong aria-hidden="true">4.2.</strong> External Navigation</a></li><li class="chapter-item expanded "><a href="features/navigation/programmatic.html"><strong aria-hidden="true">4.3.</strong> Programmatic Navigation</a></li></ol></li><li class="chapter-item expanded "><a href="features/query.html"><strong aria-hidden="true">5.</strong> Query</a></li><li class="chapter-item expanded "><a href="features/failures/index.html"><strong aria-hidden="true">6.</strong> Navigation Failures</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="features/failures/named.html"><strong aria-hidden="true">6.1.</strong> Named Navigation Failure</a></li><li class="chapter-item expanded "><a href="features/failures/external.html"><strong aria-hidden="true">6.2.</strong> External Navigation Failure</a></li><li class="chapter-item expanded "><a href="features/failures/redirection-limit.html"><strong aria-hidden="true">6.3.</strong> Redirection Limit Failure</a></li></ol></li><li class="chapter-item expanded "><a href="features/history-providers.html"><strong aria-hidden="true">7.</strong> History Providers</a></li><li class="chapter-item expanded "><a href="features/history-buttons.html"><strong aria-hidden="true">8.</strong> History Buttons</a></li><li class="chapter-item expanded "><a href="features/sitemap-generation.html"><strong aria-hidden="true">9.</strong> Sitemap Generation</a></li><li class="chapter-item expanded "><a href="features/routing-update-callback.html"><strong aria-hidden="true">10.</strong> Routing Update Callback</a></li><li class="chapter-item expanded affix "><li class="part-title">Example Project</li><li class="chapter-item expanded "><a href="example/index.html"><strong aria-hidden="true">11.</strong> Overview</a></li><li class="chapter-item expanded "><a href="example/first-route.html"><strong aria-hidden="true">12.</strong> Creating Our First Route</a></li><li class="chapter-item expanded "><a href="example/building-a-nest.html"><strong aria-hidden="true">13.</strong> Building a Nest</a></li><li class="chapter-item expanded "><a href="example/navigation-targets.html"><strong aria-hidden="true">14.</strong> Navigation Targets</a></li><li class="chapter-item expanded "><a href="example/redirection-perfection.html"><strong aria-hidden="true">15.</strong> Redirection Perfection</a></li><li class="chapter-item expanded "><a href="example/full-code.html"><strong aria-hidden="true">16.</strong> Full Code</a></li></ol>
  72. </div>
  73. <div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
  74. </nav>
  75. <div id="page-wrapper" class="page-wrapper">
  76. <div class="page">
  77. <div id="menu-bar-hover-placeholder"></div>
  78. <div id="menu-bar" class="menu-bar sticky bordered">
  79. <div class="left-buttons">
  80. <button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
  81. <i class="fa fa-bars"></i>
  82. </button>
  83. <button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
  84. <i class="fa fa-paint-brush"></i>
  85. </button>
  86. <ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
  87. <li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
  88. <li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
  89. <li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
  90. <li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
  91. <li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
  92. </ul>
  93. <button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
  94. <i class="fa fa-search"></i>
  95. </button>
  96. </div>
  97. <h1 class="menu-title">Dioxus Router</h1>
  98. <div class="right-buttons">
  99. <a href="print.html" title="Print this book" aria-label="Print this book">
  100. <i id="print-button" class="fa fa-print"></i>
  101. </a>
  102. </div>
  103. </div>
  104. <div id="search-wrapper" class="hidden">
  105. <form id="searchbar-outer" class="searchbar-outer">
  106. <input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
  107. </form>
  108. <div id="searchresults-outer" class="searchresults-outer hidden">
  109. <div id="searchresults-header" class="searchresults-header"></div>
  110. <ul id="searchresults">
  111. </ul>
  112. </div>
  113. </div>
  114. <!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
  115. <script type="text/javascript">
  116. document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
  117. document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
  118. Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
  119. link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
  120. });
  121. </script>
  122. <div id="content" class="content">
  123. <main>
  124. <h1 id="introduction"><a class="header" href="#introduction">Introduction</a></h1>
  125. <p>Whether or not you are building a website, desktop app, or mobile app,
  126. splitting your app's views into &quot;pages&quot; can be an effective method for
  127. organization and maintainability.</p>
  128. <p>For this purpose, Dioxus provides a router. To start utilizing it, add it as a
  129. dependency in your <code>Cargo.toml</code> file:</p>
  130. <pre><code class="language-toml">[dependencies]
  131. # use this for native apps
  132. dioxus-router = &quot;*&quot;
  133. #use this for web apps
  134. dioxus-router = { version = &quot;*&quot;, features = [&quot;web&quot;] }
  135. # in both cases replace * with the current version
  136. </code></pre>
  137. <p>You can also use the <code>cargo</code> command to add the dependency:</p>
  138. <pre><code class="language-sh">$ cargo add dioxus-router
  139. $ cargo add dioxus-router --features web
  140. </code></pre>
  141. <blockquote>
  142. <p>If you are not familiar with Dioxus itself, check out the <a href="https://dioxuslabs.com/guide/">Dioxus book</a>
  143. first.</p>
  144. </blockquote>
  145. <p>This book is intended to get you up to speed with Dioxus Router. It is split
  146. into two sections:</p>
  147. <ol>
  148. <li>The <a href="./features/index.html">Features</a> part explains individual features in
  149. depth. You can read it start to finish, or you can read individual chapters
  150. in whatever order you want.</li>
  151. <li>If you prefer a learning-by-doing approach, you can check ouf the
  152. <em><a href="./example/introduction.html">example project</a></em>. It guides you through
  153. creating a dioxus app, setting up the router and using some of its
  154. functionality.</li>
  155. </ol>
  156. <blockquote>
  157. <p>Please note that this is not the only documentation for the Dioxus Router. You
  158. can also check out the <a href="https://docs.rs/dioxus-router/">API Docs</a>.</p>
  159. </blockquote>
  160. <div style="break-before: page; page-break-before: always;"></div><h1 id="adding-the-router-to-your-application"><a class="header" href="#adding-the-router-to-your-application">Adding the Router to Your Application</a></h1>
  161. <p>In this chapter we will learn how to add the router to our app. By it self, this
  162. is not very useful. However, it is a prerequisite for all the functionality
  163. described in the other chapters.</p>
  164. <blockquote>
  165. <p>Make sure you added the <code>dioxus-router</code> dependency as explained in the
  166. <a href="features/../index.html">introduction</a>.</p>
  167. </blockquote>
  168. <p>In most cases we want to add the router to the root component of our app. This
  169. way, we can ensure that we have access to all its functionality everywhere. We
  170. add it by using the <a href="https://docs.rs/dioxus-router/latest/dioxus_router/hooks/fn.use_router.html"><code>use_router</code></a> hook</p>
  171. <pre><pre class="playground"><code class="language-rust edition2021">
  172. <span class="boring">#![allow(unused)]
  173. </span><span class="boring">fn main() {
  174. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  175. </span><span class="boring">extern crate dioxus;
  176. </span>use dioxus::prelude::*;
  177. <span class="boring">extern crate dioxus_router;
  178. </span>use dioxus_router::prelude::*;
  179. <span class="boring">extern crate dioxus_ssr;
  180. </span>
  181. // This is the component we pass to dioxus when launching our app.
  182. fn App(cx: Scope) -&gt; Element {
  183. // Here we add the router. All components inside `App` have access to its
  184. // functionality.
  185. let routes = use_router(
  186. cx,
  187. // The router can be configured with this parameter.
  188. &amp;|| RouterConfiguration {
  189. <span class="boring"> synchronous: true,
  190. </span> ..Default::default()
  191. },
  192. // This tells the router about all the routes in our application. As we
  193. // don't have any, we pass an empty segment
  194. &amp;|| Segment::empty()
  195. );
  196. render! {
  197. h1 { &quot;Our sites title&quot; }
  198. // The Outlet tells the Router where to render active content.
  199. Outlet { }
  200. }
  201. }
  202. <span class="boring">
  203. </span><span class="boring">let mut vdom = VirtualDom::new(App);
  204. </span><span class="boring">let _ = vdom.rebuild();
  205. </span><span class="boring">assert_eq!(
  206. </span><span class="boring"> dioxus_ssr::render(&amp;vdom),
  207. </span><span class="boring"> &quot;&lt;h1&gt;Our sites title&lt;/h1&gt;&quot;
  208. </span><span class="boring">);
  209. </span><span class="boring">}
  210. </span></code></pre></pre>
  211. <div style="break-before: page; page-break-before: always;"></div><h1 id="defining-routes"><a class="header" href="#defining-routes">Defining Routes</a></h1>
  212. <p>When creating a router we need to pass it a <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/routes/struct.Segment.html"><code>Segment</code></a>. It tells the router
  213. about all the routes of our app.</p>
  214. <h2 id="example-content"><a class="header" href="#example-content">Example content</a></h2>
  215. <p>To get a good understanding of how we define routes we first need to prepare
  216. some example content, so we can see the routing in action.</p>
  217. <pre><pre class="playground"><code class="language-rust no_run edition2021">
  218. <span class="boring">#![allow(unused)]
  219. </span><span class="boring">fn main() {
  220. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  221. </span><span class="boring">extern crate dioxus;
  222. </span>use dioxus::prelude::*;
  223. <span class="boring">extern crate dioxus_router;
  224. </span>use dioxus_router::prelude::*;
  225. fn Index(cx: Scope) -&gt; Element {
  226. render! {
  227. h1 { &quot;Welcome to our test site!&quot; }
  228. }
  229. }
  230. fn Other(cx: Scope) -&gt; Element {
  231. render! {
  232. p { &quot;some other content&quot; }
  233. }
  234. }
  235. <span class="boring">}
  236. </span></code></pre></pre>
  237. <h2 id="index-routes"><a class="header" href="#index-routes">Index routes</a></h2>
  238. <p>The easiest thing to do is to define an index route.</p>
  239. <p>Index routes act very similar to <code>index.html</code> files in most web servers. They
  240. are active, when we don't specify a route.</p>
  241. <blockquote>
  242. <p>Note that we wrap our <code>Index</code> component with <a href="https://docs.rs/dioxus-router/latest/dioxus_router/prelude/fn.comp.html"><code>comp</code></a>. This is because of
  243. rust type system requirements.</p>
  244. </blockquote>
  245. <pre><pre class="playground"><code class="language-rust no_run edition2021">
  246. <span class="boring">#![allow(unused)]
  247. </span><span class="boring">fn main() {
  248. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  249. </span><span class="boring">extern crate dioxus;
  250. </span><span class="boring">use dioxus::prelude::*;
  251. </span><span class="boring">extern crate dioxus_router;
  252. </span><span class="boring">use dioxus_router::prelude::*;
  253. </span><span class="boring">fn Index(cx: Scope) -&gt; Element { unimplemented!() }
  254. </span><span class="boring">
  255. </span>fn App(cx: Scope) -&gt; Element {
  256. use_router(
  257. cx,
  258. &amp;|| RouterConfiguration {
  259. ..Default::default()
  260. },
  261. &amp;|| Segment::content(comp(Index))
  262. );
  263. // ...
  264. <span class="boring"> unimplemented!()
  265. </span>}
  266. <span class="boring">}
  267. </span></code></pre></pre>
  268. <h2 id="fixed-routes"><a class="header" href="#fixed-routes">Fixed routes</a></h2>
  269. <p>It is almost as easy to define a fixed route.</p>
  270. <p>Fixed routes work similar to how web servers treat files. They are active, when
  271. specified in the path. In the example, the path must be <code>/other</code>.</p>
  272. <blockquote>
  273. <p>The path will be URL decoded before checking if it matches our route.</p>
  274. </blockquote>
  275. <pre><pre class="playground"><code class="language-rust no_run edition2021">
  276. <span class="boring">#![allow(unused)]
  277. </span><span class="boring">fn main() {
  278. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  279. </span><span class="boring">extern crate dioxus;
  280. </span><span class="boring">use dioxus::prelude::*;
  281. </span><span class="boring">extern crate dioxus_router;
  282. </span><span class="boring">use dioxus_router::prelude::*;
  283. </span><span class="boring">fn Index(cx: Scope) -&gt; Element { unimplemented!() }
  284. </span><span class="boring">fn Other(cx: Scope) -&gt; Element { unimplemented!() }
  285. </span><span class="boring">
  286. </span>fn App(cx: Scope) -&gt; Element {
  287. use_router(
  288. cx,
  289. &amp;|| RouterConfiguration {
  290. ..Default::default()
  291. },
  292. &amp;|| Segment::content(comp(Index)).fixed(&quot;other&quot;, comp(Other))
  293. // ^ note the absence of a / prefix
  294. );
  295. // ...
  296. <span class="boring"> unimplemented!()
  297. </span>}
  298. <span class="boring">}
  299. </span></code></pre></pre>
  300. <h2 id="full-code"><a class="header" href="#full-code">Full Code</a></h2>
  301. <pre><pre class="playground"><code class="language-rust edition2021">
  302. <span class="boring">#![allow(unused)]
  303. </span><span class="boring">fn main() {
  304. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  305. </span><span class="boring">extern crate dioxus;
  306. </span>use dioxus::prelude::*;
  307. <span class="boring">extern crate dioxus_router;
  308. </span>use dioxus_router::{history::MemoryHistory, prelude::*};
  309. <span class="boring">extern crate dioxus_ssr;
  310. </span>
  311. fn Index(cx: Scope) -&gt; Element {
  312. render! {
  313. h1 { &quot;Welcome to our test site!&quot; }
  314. }
  315. }
  316. fn Other(cx: Scope) -&gt; Element {
  317. render! {
  318. p { &quot;some other content&quot; }
  319. }
  320. }
  321. fn App(cx: Scope) -&gt; Element {
  322. use_router(
  323. cx,
  324. &amp;|| RouterConfiguration {
  325. <span class="boring"> synchronous: true,
  326. </span><span class="boring"> history: Box::new(MemoryHistory::with_initial_path(&quot;/other&quot;).unwrap()),
  327. </span> ..Default::default()
  328. },
  329. &amp;|| Segment::content(comp(Index)).fixed(&quot;other&quot;, comp(Other))
  330. );
  331. render! {
  332. Outlet { }
  333. }
  334. }
  335. <span class="boring">
  336. </span><span class="boring">let mut vdom = VirtualDom::new(App);
  337. </span><span class="boring">vdom.rebuild();
  338. </span><span class="boring">assert_eq!(
  339. </span><span class="boring"> dioxus_ssr::render(&amp;vdom),
  340. </span><span class="boring"> &quot;&lt;p&gt;some other content&lt;/p&gt;&quot;
  341. </span><span class="boring">);
  342. </span><span class="boring">}
  343. </span></code></pre></pre>
  344. <div style="break-before: page; page-break-before: always;"></div><h1 id="nested-routes"><a class="header" href="#nested-routes">Nested Routes</a></h1>
  345. <p>When developing bigger applications we often want to nest routes within each
  346. other. As an example, we might want to organize a settings menu using this
  347. pattern:</p>
  348. <pre><code class="language-plain">└ Settings
  349. ├ General Settings (displayed when opening the settings)
  350. ├ Change Password
  351. └ Privacy Settings
  352. </code></pre>
  353. <p>We might want to map this structure to these paths and components:</p>
  354. <pre><code class="language-plain">/settings -&gt; Settings { GeneralSettings }
  355. /settings/password -&gt; Settings { PWSettings }
  356. /settings/privacy -&gt; Settings { PrivacySettings }
  357. </code></pre>
  358. <p>Nested routes allow us to do this.</p>
  359. <h2 id="route-depth"><a class="header" href="#route-depth">Route Depth</a></h2>
  360. <p>With nesting routes, the router manages content on multiple levels. In our
  361. example, when the path is <code>/settings</code>, there are two levels of content:</p>
  362. <ol start="0">
  363. <li>The <code>Settings</code> component</li>
  364. <li>The <code>GeneralSettings</code> component</li>
  365. </ol>
  366. <p>Dioxus Router uses the <a href="https://docs.rs/dioxus-router/latest/dioxus_router/components/fn.Outlet.html"><code>Outlet</code></a> component to actually render content, but each
  367. <a href="https://docs.rs/dioxus-router/latest/dioxus_router/components/fn.Outlet.html"><code>Outlet</code></a> can only render content from one level. This means that for the
  368. content of nested routes to actually be rendered, we also need nested
  369. <a href="https://docs.rs/dioxus-router/latest/dioxus_router/components/fn.Outlet.html"><code>Outlet</code></a>s.</p>
  370. <h2 id="defining-the-content-components"><a class="header" href="#defining-the-content-components">Defining the content components</a></h2>
  371. <p>We start by creating the components we want the router to render.</p>
  372. <p>Take a look at the <code>Settings</code> component. When it gets rendered by an <a href="https://docs.rs/dioxus-router/latest/dioxus_router/components/fn.Outlet.html"><code>Outlet</code></a>,
  373. it will render a second <a href="https://docs.rs/dioxus-router/latest/dioxus_router/components/fn.Outlet.html"><code>Outlet</code></a>. Thus the second <a href="https://docs.rs/dioxus-router/latest/dioxus_router/components/fn.Outlet.html"><code>Outlet</code></a> is nested within
  374. the first one, and will in turn render our nested content.</p>
  375. <pre><pre class="playground"><code class="language-rust no_run edition2021">
  376. <span class="boring">#![allow(unused)]
  377. </span><span class="boring">fn main() {
  378. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  379. </span><span class="boring">extern crate dioxus;
  380. </span><span class="boring">use dioxus::prelude::*;
  381. </span><span class="boring">extern crate dioxus_router;
  382. </span><span class="boring">use dioxus_router::prelude::*;
  383. </span><span class="boring">
  384. </span>fn Settings(cx: Scope) -&gt; Element {
  385. render! {
  386. h1 { &quot;Settings&quot; }
  387. Outlet { }
  388. }
  389. }
  390. fn GeneralSettings(cx: Scope) -&gt; Element {
  391. render! {
  392. h2 { &quot;General Settings&quot; }
  393. }
  394. }
  395. fn PWSettings(cx: Scope) -&gt; Element {
  396. render! {
  397. h2 { &quot;Password Settings&quot; }
  398. }
  399. }
  400. fn PrivacySettings(cx: Scope) -&gt; Element {
  401. render! {
  402. h2 { &quot;Privacy Settings&quot; }
  403. }
  404. }
  405. <span class="boring">}
  406. </span></code></pre></pre>
  407. <h2 id="defining-the-root-segment"><a class="header" href="#defining-the-root-segment">Defining the root <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/routes/struct.Segment.html"><code>Segment</code></a></a></h2>
  408. <p>Now we create the <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/routes/struct.Segment.html"><code>Segment</code></a> that we will pass to the router.</p>
  409. <p>Note that we wrap <code>comp(Settings)</code> within a <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/routes/struct.Route.html"><code>Route</code></a>. For this exact code that
  410. is unnecessary, as this would be done automatically. However, in the next step
  411. we'll use a method of <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/routes/struct.Route.html"><code>Route</code></a>, so we might as well add this now.</p>
  412. <pre><pre class="playground"><code class="language-rust no_run edition2021">
  413. <span class="boring">#![allow(unused)]
  414. </span><span class="boring">fn main() {
  415. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  416. </span><span class="boring">extern crate dioxus;
  417. </span><span class="boring">use dioxus::prelude::*;
  418. </span><span class="boring">extern crate dioxus_router;
  419. </span><span class="boring">use dioxus_router::prelude::*;
  420. </span><span class="boring">fn Settings(cx: Scope) -&gt; Element { unimplemented!() }
  421. </span><span class="boring">
  422. </span>fn App(cx: Scope) -&gt; Element {
  423. use_router(
  424. cx,
  425. &amp;|| RouterConfiguration {
  426. ..Default::default()
  427. },
  428. &amp;|| Segment::empty().fixed(&quot;settings&quot;, Route::content(comp(Settings)))
  429. );
  430. // ...
  431. <span class="boring"> unimplemented!()
  432. </span>}
  433. <span class="boring">}
  434. </span></code></pre></pre>
  435. <h2 id="defining-the-nested-segment"><a class="header" href="#defining-the-nested-segment">Defining the nested <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/routes/struct.Segment.html"><code>Segment</code></a></a></h2>
  436. <p>In order to create nested routes we need to create a nested <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/routes/struct.Segment.html"><code>Segment</code></a>. We then
  437. pass it to the <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/routes/struct.Route.html"><code>Route</code></a> on the root segment.</p>
  438. <blockquote>
  439. <p>A <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/routes/struct.Segment.html"><code>Segment</code></a> always refers to one exact segment of the path.</p>
  440. <p>https://router.example/<code>root_segment</code>/<code>first_nested_segment</code>/<code>second_nested_segment</code>/...</p>
  441. </blockquote>
  442. <pre><pre class="playground"><code class="language-rust no_run edition2021">
  443. <span class="boring">#![allow(unused)]
  444. </span><span class="boring">fn main() {
  445. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  446. </span><span class="boring">extern crate dioxus;
  447. </span><span class="boring">use dioxus::prelude::*;
  448. </span><span class="boring">extern crate dioxus_router;
  449. </span><span class="boring">use dioxus_router::prelude::*;
  450. </span><span class="boring">fn Settings(cx: Scope) -&gt; Element { unimplemented!() }
  451. </span><span class="boring">fn GeneralSettings(cx: Scope) -&gt; Element { unimplemented!() }
  452. </span><span class="boring">fn PWSettings(cx: Scope) -&gt; Element { unimplemented!() }
  453. </span><span class="boring">fn PrivacySettings(cx: Scope) -&gt; Element { unimplemented!() }
  454. </span><span class="boring">
  455. </span>fn App(cx: Scope) -&gt; Element {
  456. use_router(
  457. cx,
  458. &amp;|| RouterConfiguration {
  459. ..Default::default()
  460. },
  461. &amp;|| Segment::empty().fixed(
  462. &quot;settings&quot;,
  463. Route::content(comp(Settings)).nested(
  464. Segment::content(comp(GeneralSettings))
  465. .fixed(&quot;password&quot;, comp(PWSettings))
  466. .fixed(&quot;privacy&quot;, comp(PrivacySettings))
  467. )
  468. )
  469. );
  470. // ...
  471. <span class="boring"> unimplemented!()
  472. </span>}
  473. <span class="boring">}
  474. </span></code></pre></pre>
  475. <h2 id="full-code-1"><a class="header" href="#full-code-1">Full Code</a></h2>
  476. <pre><pre class="playground"><code class="language-rust edition2021">
  477. <span class="boring">#![allow(unused)]
  478. </span><span class="boring">fn main() {
  479. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  480. </span><span class="boring">extern crate dioxus;
  481. </span><span class="boring">use dioxus::prelude::*;
  482. </span><span class="boring">extern crate dioxus_router;
  483. </span><span class="boring">use dioxus_router::{history::MemoryHistory, prelude::*};
  484. </span><span class="boring">extern crate dioxus_ssr;
  485. </span><span class="boring">
  486. </span>fn Settings(cx: Scope) -&gt; Element {
  487. render! {
  488. h1 { &quot;Settings&quot; }
  489. Outlet { }
  490. }
  491. }
  492. fn GeneralSettings(cx: Scope) -&gt; Element {
  493. render! {
  494. h2 { &quot;General Settings&quot; }
  495. }
  496. }
  497. fn PWSettings(cx: Scope) -&gt; Element {
  498. render! {
  499. h2 { &quot;Password Settings&quot; }
  500. }
  501. }
  502. fn PrivacySettings(cx: Scope) -&gt; Element {
  503. render! {
  504. h2 { &quot;Privacy Settings&quot; }
  505. }
  506. }
  507. fn App(cx: Scope) -&gt; Element {
  508. use_router(
  509. cx,
  510. &amp;|| RouterConfiguration {
  511. <span class="boring"> synchronous: true,
  512. </span><span class="boring"> history: Box::new(MemoryHistory::with_initial_path(&quot;/settings/privacy&quot;).unwrap()),
  513. </span> ..Default::default()
  514. },
  515. &amp;|| Segment::empty().fixed(
  516. &quot;settings&quot;,
  517. Route::content(comp(Settings)).nested(
  518. Segment::content(comp(GeneralSettings))
  519. .fixed(&quot;password&quot;, comp(PWSettings))
  520. .fixed(&quot;privacy&quot;, comp(PrivacySettings))
  521. )
  522. )
  523. );
  524. render! {
  525. Outlet { }
  526. }
  527. }
  528. <span class="boring">
  529. </span><span class="boring">let mut vdom = VirtualDom::new(App);
  530. </span><span class="boring">vdom.rebuild();
  531. </span><span class="boring">assert_eq!(
  532. </span><span class="boring"> dioxus_ssr::render(&amp;vdom),
  533. </span><span class="boring"> &quot;&lt;h1&gt;Settings&lt;/h1&gt;&lt;h2&gt;Privacy Settings&lt;/h2&gt;&quot;
  534. </span><span class="boring">);
  535. </span><span class="boring">}
  536. </span></code></pre></pre>
  537. <div style="break-before: page; page-break-before: always;"></div><h1 id="catch-all-routes"><a class="header" href="#catch-all-routes">Catch All Routes</a></h1>
  538. <p>Many modern web apps store parameters within their current path. This allows
  539. users to share URLs that link to a specific bit of content. We can create this
  540. functionality with catch all routes.</p>
  541. <blockquote>
  542. <p>If you want to change what route is active based on the format of the
  543. parameter, see <a href="features/routes/./matching.html">Matching Routes</a>.</p>
  544. </blockquote>
  545. <blockquote>
  546. <p>The parameter will be URL decoded.</p>
  547. </blockquote>
  548. <h2 id="creating-a-content-component"><a class="header" href="#creating-a-content-component">Creating a content component</a></h2>
  549. <p>We start by creating a component that uses the parameters value.</p>
  550. <p>We can get the current state of the router using the <a href="https://docs.rs/dioxus-router/latest/dioxus_router/hooks/fn.use_route.html"><code>use_route</code></a> hook. From
  551. that state we can extract the current value of our parameter by using a key we
  552. will later also define on our route.</p>
  553. <blockquote>
  554. <p>It is <strong>VERY IMPORTANT</strong> to drop the object returned by the <a href="https://docs.rs/dioxus-router/latest/dioxus_router/hooks/fn.use_route.html"><code>use_route</code></a>
  555. hook once our component finished rendering. Otherwise the entire router will
  556. be frozen.</p>
  557. </blockquote>
  558. <blockquote>
  559. <p>The <a href="https://docs.rs/dioxus-router/latest/dioxus_router/hooks/fn.use_route.html"><code>use_route</code></a> hook can only be used in components nested within a
  560. component that called <a href="https://docs.rs/dioxus-router/latest/dioxus_router/hooks/fn.use_router.html"><code>use_router</code></a>.</p>
  561. </blockquote>
  562. <pre><pre class="playground"><code class="language-rust no_run edition2021">
  563. <span class="boring">#![allow(unused)]
  564. </span><span class="boring">fn main() {
  565. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  566. </span><span class="boring">extern crate dioxus;
  567. </span>use dioxus::prelude::*;
  568. <span class="boring">extern crate dioxus_router;
  569. </span>use dioxus_router::prelude::*;
  570. struct Name;
  571. fn Greeting(cx: Scope) -&gt; Element {
  572. let route = use_route(cx).expect(&quot;is nested within a Router component&quot;);
  573. let name = route.parameter::&lt;Name&gt;()
  574. .map(|name| name.clone())
  575. .unwrap_or(String::from(&quot;world&quot;));
  576. render! {
  577. p { &quot;Hello, {name}!&quot; }
  578. }
  579. }
  580. <span class="boring">}
  581. </span></code></pre></pre>
  582. <h2 id="defining-the-routes"><a class="header" href="#defining-the-routes">Defining the routes</a></h2>
  583. <p>Now we can define our route. Unlike a fixed <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/routes/struct.Route.html"><code>Route</code></a>, a <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/routes/struct.ParameterRoute.html"><code>ParameterRoute</code></a>
  584. needs two arguments to be created.</p>
  585. <blockquote>
  586. <p>Also note that each <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/routes/struct.Segment.html"><code>Segment</code></a> can have exactly one parameter or
  587. <a href="features/routes/./fallback.html">fallback route</a>.</p>
  588. <p>For that reason, the example below would not work in practice, but showing
  589. both forms (explicit and short) is more important for this example.</p>
  590. </blockquote>
  591. <pre><pre class="playground"><code class="language-rust no_run edition2021">
  592. <span class="boring">#![allow(unused)]
  593. </span><span class="boring">fn main() {
  594. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  595. </span><span class="boring">extern crate dioxus;
  596. </span><span class="boring">use dioxus::prelude::*;
  597. </span><span class="boring">extern crate dioxus_router;
  598. </span><span class="boring">use dioxus_router::prelude::*;
  599. </span><span class="boring">fn Greeting(cx: Scope) -&gt; Element { unimplemented!() }
  600. </span><span class="boring">
  601. </span>struct Name;
  602. fn App(cx: Scope) -&gt; Element {
  603. use_router(
  604. cx,
  605. &amp;|| RouterConfiguration {
  606. ..Default::default()
  607. },
  608. &amp;|| {
  609. Segment::empty()
  610. .catch_all(ParameterRoute::content::&lt;Name&gt;(comp(Greeting)))
  611. .catch_all((comp(Greeting), Name { })) // same in short
  612. }
  613. );
  614. // ...
  615. <span class="boring"> unimplemented!()
  616. </span>}
  617. <span class="boring">}
  618. </span></code></pre></pre>
  619. <h2 id="interaction-with-other-routes"><a class="header" href="#interaction-with-other-routes">Interaction with other routes</a></h2>
  620. <p>Each individual <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/routes/struct.Segment.html"><code>Segment</code></a> can only ever have one active route. This means that
  621. when a <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/routes/struct.Segment.html"><code>Segment</code></a> has more than just a catch all route, the router has to
  622. decide which is active. It does that this way:</p>
  623. <ol start="0">
  624. <li>If the segment is not specified (i.e. <code>/</code>), then the index route will be
  625. active.</li>
  626. <li>If a <a href="features/routes/./index.html#fixed-routes"><em>fixed</em></a> route matches the current path, it
  627. will be active.</li>
  628. <li>If a <a href="features/routes/./matching.html"><em>matching</em> route</a> matches the current path, it will be
  629. active. <em>Matching</em> routes are checked in the order they are defined.</li>
  630. <li>If neither a <em>fixed</em> nor a <em>matching</em> route is active, the <em>catch all</em> route
  631. or <a href="features/routes/./fallback.html"><em>fallback</em> route</a> will be.</li>
  632. </ol>
  633. <p>Step 0 means that if we want a parameter to be empty, that needs to be specified
  634. by the path, i.e. <code>//</code>.</p>
  635. <blockquote>
  636. <p>Be careful with using catch all routes on the root <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/routes/struct.Segment.html"><code>Segment</code></a>. Navigating to
  637. paths starting with <code>//</code> will <strong>NOT</strong> work. This is not a limitation of the
  638. router, but rather of how relative URLs work.</p>
  639. <p>If you absolutely need an empty parameter on the root <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/routes/struct.Segment.html"><code>Segment</code></a>, a URL like
  640. this <em>could</em> work:</p>
  641. <ul>
  642. <li><code>https://your-site.example//</code> for web sites</li>
  643. <li><code>dioxus://index.html//</code> for desktop apps</li>
  644. </ul>
  645. </blockquote>
  646. <h2 id="full-code-2"><a class="header" href="#full-code-2">Full Code</a></h2>
  647. <pre><pre class="playground"><code class="language-rust edition2021">
  648. <span class="boring">#![allow(unused)]
  649. </span><span class="boring">fn main() {
  650. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  651. </span><span class="boring">extern crate dioxus;
  652. </span><span class="boring">use dioxus::prelude::*;
  653. </span><span class="boring">extern crate dioxus_router;
  654. </span><span class="boring">use dioxus_router::{history::MemoryHistory, prelude::*};
  655. </span><span class="boring">extern crate dioxus_ssr;
  656. </span><span class="boring">
  657. </span>struct Name;
  658. fn Greeting(cx: Scope) -&gt; Element {
  659. let route = use_route(cx).expect(&quot;is nested within a Router component&quot;);
  660. let name = route.parameter::&lt;Name&gt;()
  661. .map(|name| name.clone())
  662. .unwrap_or(String::from(&quot;world&quot;));
  663. render! {
  664. p { &quot;Hello, {name}!&quot; }
  665. }
  666. }
  667. fn App(cx: Scope) -&gt; Element {
  668. let routes = use_router(
  669. cx,
  670. &amp;|| RouterConfiguration {
  671. <span class="boring"> synchronous: true,
  672. </span><span class="boring"> history: Box::new(MemoryHistory::with_initial_path(&quot;/Dioxus&quot;).unwrap()),
  673. </span> ..Default::default()
  674. },
  675. &amp;|| Segment::empty().catch_all((comp(Greeting), Name { }))
  676. );
  677. // ...
  678. render! {
  679. Outlet { }
  680. }
  681. }
  682. <span class="boring">
  683. </span><span class="boring">let mut vdom = VirtualDom::new(App);
  684. </span><span class="boring">vdom.rebuild();
  685. </span><span class="boring">assert_eq!(
  686. </span><span class="boring"> dioxus_ssr::render(&amp;vdom),
  687. </span><span class="boring"> &quot;&lt;p&gt;Hello, Dioxus!&lt;/p&gt;&quot;
  688. </span><span class="boring">);
  689. </span><span class="boring">}
  690. </span></code></pre></pre>
  691. <div style="break-before: page; page-break-before: always;"></div><h1 id="matching-routes"><a class="header" href="#matching-routes">Matching Routes</a></h1>
  692. <blockquote>
  693. <p>Make sure you understand how <a href="features/routes/./catch_all.html">catch all routes</a> work before
  694. reading this page.</p>
  695. </blockquote>
  696. <p>When accepting parameters via the path, some complex applications might need to
  697. decide what route should be active based on the format of that parameter.
  698. <em>Matching</em> routes make it easy to implement such behavior.</p>
  699. <blockquote>
  700. <p>The parameter will be URL decoded, both for checking if the route is active
  701. and when it is provided to the application.</p>
  702. </blockquote>
  703. <blockquote>
  704. <p>The example below is only for showing <em>matching route</em> functionality. It is
  705. unfit for all other purposes.</p>
  706. </blockquote>
  707. <h2 id="code-example"><a class="header" href="#code-example">Code Example</a></h2>
  708. <blockquote>
  709. <p>Notice that the parameter of a <em>matching route</em> has the same type as a
  710. <a href="features/routes/./catch_all.html"><em>catch all route</em></a>.</p>
  711. </blockquote>
  712. <pre><pre class="playground"><code class="language-rust edition2021">
  713. <span class="boring">#![allow(unused)]
  714. </span><span class="boring">fn main() {
  715. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  716. </span><span class="boring">extern crate dioxus;
  717. </span><span class="boring">use dioxus::prelude::*;
  718. </span><span class="boring">extern crate dioxus_router;
  719. </span><span class="boring">use dioxus_router::{history::MemoryHistory, prelude::*};
  720. </span><span class="boring">extern crate dioxus_ssr;
  721. </span><span class="boring">extern crate regex;
  722. </span>use regex::Regex;
  723. struct Name;
  724. fn GreetingFemale(cx: Scope) -&gt; Element {
  725. let route = use_route(cx).unwrap();
  726. let name = route.parameter::&lt;Name&gt;()
  727. .map(|name| {
  728. let mut name = name.to_string();
  729. name.remove(0);
  730. name
  731. })
  732. .unwrap_or(String::from(&quot;Anonymous&quot;));
  733. render! {
  734. p { &quot;Hello Mrs. {name}&quot; }
  735. }
  736. }
  737. fn GreetingMale(cx: Scope) -&gt; Element {
  738. let route = use_route(cx).unwrap();
  739. let name = route.parameter::&lt;Name&gt;()
  740. .map(|name| {
  741. let mut name = name.to_string();
  742. name.remove(0);
  743. name
  744. })
  745. .unwrap_or(String::from(&quot;Anonymous&quot;));
  746. render! {
  747. p { &quot;Hello Mr. {name}&quot; }
  748. }
  749. }
  750. fn GreetingWithoutGender(cx: Scope) -&gt; Element {
  751. let route = use_route(cx).unwrap();
  752. let name = route.parameter::&lt;Name&gt;()
  753. .map(|name| name.to_string())
  754. .unwrap_or(String::from(&quot;Anonymous&quot;));
  755. render! {
  756. p { &quot;Hello {name}&quot; }
  757. }
  758. }
  759. fn GreetingKenobi(cx: Scope) -&gt; Element {
  760. render! {
  761. p { &quot;Hello there.&quot; }
  762. p { &quot;General Kenobi.&quot; }
  763. }
  764. }
  765. fn App(cx: Scope) -&gt; Element {
  766. use_router(
  767. cx,
  768. &amp;|| RouterConfiguration {
  769. <span class="boring"> synchronous: true,
  770. </span><span class="boring"> history: Box::new(MemoryHistory::with_initial_path(&quot;/fAnna&quot;).unwrap()),
  771. </span> ..Default::default()
  772. },
  773. &amp;|| {
  774. Segment::empty()
  775. .fixed(&quot;kenobi&quot;, comp(GreetingKenobi))
  776. .matching(
  777. Regex::new(&quot;^f&quot;).unwrap(),
  778. ParameterRoute::content::&lt;Name&gt;(comp(GreetingFemale))
  779. )
  780. .matching(
  781. Regex::new(&quot;^m&quot;).unwrap(),
  782. (comp(GreetingMale), Name { })
  783. )
  784. .catch_all((comp(GreetingWithoutGender), Name { }))
  785. }
  786. );
  787. render! {
  788. Outlet { }
  789. }
  790. }
  791. <span class="boring">
  792. </span><span class="boring">let mut vdom = VirtualDom::new(App);
  793. </span><span class="boring">vdom.rebuild();
  794. </span><span class="boring">let html = dioxus_ssr::render(&amp;vdom);
  795. </span><span class="boring">assert_eq!(html, &quot;&lt;p&gt;Hello Mrs. Anna&lt;/p&gt;&quot;);
  796. </span><span class="boring">}
  797. </span></code></pre></pre>
  798. <h2 id="matcher"><a class="header" href="#matcher">Matcher</a></h2>
  799. <p>In the example above, both <em>matching routes</em> use a regular expression to specify
  800. when they match. However, <em>matching routes</em> are not limited to those. They
  801. accept all types that implement the <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/routes/trait.Matcher.html"><code>Matcher</code></a> trait.</p>
  802. <p>For example, you could (but probably shouldn't) implement a matcher, that
  803. matches all values with an even number of characters:</p>
  804. <pre><pre class="playground"><code class="language-rust no_run edition2021">
  805. <span class="boring">#![allow(unused)]
  806. </span><span class="boring">fn main() {
  807. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  808. </span><span class="boring">extern crate dioxus_router;
  809. </span><span class="boring">use dioxus_router::prelude::*;
  810. </span><span class="boring">
  811. </span>#[derive(Debug)]
  812. struct EvenMatcher;
  813. impl Matcher for EvenMatcher {
  814. fn matches(&amp;self, value: &amp;str) -&gt; bool {
  815. value.len() % 2 == 0
  816. }
  817. }
  818. <span class="boring">}
  819. </span></code></pre></pre>
  820. <div style="break-before: page; page-break-before: always;"></div><h1 id="fallback-routes"><a class="header" href="#fallback-routes">Fallback Routes</a></h1>
  821. <p>Sometimes the router might be unable to find a route for the provided path. We
  822. might want it to show a prepared error message to our users in that case.
  823. Fallback routes allow us to do that.</p>
  824. <blockquote>
  825. <p>This is especially important for use cases where users can manually change the
  826. path, like web apps running in the browser.</p>
  827. </blockquote>
  828. <h2 id="a-single-global-fallback"><a class="header" href="#a-single-global-fallback">A single global fallback</a></h2>
  829. <p>To catch all cases of invalid paths within our app, we can simply add a fallback
  830. route to our root <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/routes/struct.Segment.html"><code>Segment</code></a>.</p>
  831. <pre><pre class="playground"><code class="language-rust edition2021">
  832. <span class="boring">#![allow(unused)]
  833. </span><span class="boring">fn main() {
  834. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  835. </span><span class="boring">extern crate dioxus;
  836. </span>use dioxus::prelude::*;
  837. <span class="boring">extern crate dioxus_router;
  838. </span>use dioxus_router::{history::MemoryHistory, prelude::*};
  839. <span class="boring">extern crate dioxus_ssr;
  840. </span>
  841. fn Index(cx: Scope) -&gt; Element {
  842. render! {
  843. h1 { &quot;Index&quot; }
  844. }
  845. }
  846. fn Fallback(cx: Scope) -&gt; Element {
  847. render! {
  848. h1 { &quot;Error 404 - Not Found&quot; }
  849. p { &quot;The page you asked for doesn't exist.&quot; }
  850. }
  851. }
  852. fn App(cx: Scope) -&gt; Element {
  853. use_router(
  854. cx,
  855. &amp;|| RouterConfiguration {
  856. <span class="boring"> synchronous: true,
  857. </span><span class="boring"> history: Box::new(MemoryHistory::with_initial_path(&quot;/invalid&quot;).unwrap()),
  858. </span> ..Default::default()
  859. },
  860. &amp;|| {
  861. Segment::content(comp(Index)).fallback(comp(Fallback))
  862. }
  863. );
  864. render! {
  865. Outlet { }
  866. }
  867. }
  868. <span class="boring">
  869. </span><span class="boring">let mut vdom = VirtualDom::new(App);
  870. </span><span class="boring">vdom.rebuild();
  871. </span><span class="boring">assert_eq!(
  872. </span><span class="boring"> dioxus_ssr::render(&amp;vdom),
  873. </span><span class="boring"> &quot;&lt;h1&gt;Error 404 - Not Found&lt;/h1&gt;&lt;p&gt;The page you asked for doesn't exist.&lt;/p&gt;&quot;
  874. </span><span class="boring">);
  875. </span><span class="boring">}
  876. </span></code></pre></pre>
  877. <h2 id="more-specific-fallback-routes"><a class="header" href="#more-specific-fallback-routes">More specific fallback routes</a></h2>
  878. <p>In some cases we might want to show different fallback content depending on what
  879. section of our app the user is in.</p>
  880. <p>For example, our app might have several settings pages under <code>/settings</code>, such
  881. as the password settings <code>/settings/password</code> or the privacy settings
  882. <code>/settings/privacy</code>. When our user is in the settings section, we want to show
  883. them <em>&quot;settings not found&quot;</em> instead of <em>&quot;page not found&quot;</em>.</p>
  884. <p>We can easily do that by setting a fallback route on our nested <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/routes/struct.Segment.html"><code>Segment</code></a>. It
  885. will then replace the global fallback whenever our <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/routes/struct.Segment.html"><code>Segment</code></a> was active.</p>
  886. <p>Note the <code>.clear_fallback(false)</code> part. If we didn't add this, the fallback
  887. content would be rendered inside the <code>Settings</code> component.</p>
  888. <pre><pre class="playground"><code class="language-rust edition2021">
  889. <span class="boring">#![allow(unused)]
  890. </span><span class="boring">fn main() {
  891. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  892. </span><span class="boring">extern crate dioxus;
  893. </span>use dioxus::prelude::*;
  894. <span class="boring">extern crate dioxus_router;
  895. </span>use dioxus_router::{history::MemoryHistory, prelude::*};
  896. <span class="boring">extern crate dioxus_ssr;
  897. </span>
  898. // This example doesn't show the index or settings components. It only shows how
  899. // to set up several fallback routes.
  900. <span class="boring">fn Index(cx: Scope) -&gt; Element { unimplemented!() }
  901. </span><span class="boring">fn Settings(cx: Scope) -&gt; Element { unimplemented!() }
  902. </span><span class="boring">fn GeneralSettings(cx: Scope) -&gt; Element { unimplemented!() }
  903. </span><span class="boring">fn PasswordSettings(cx: Scope) -&gt; Element { unimplemented!() }
  904. </span><span class="boring">fn PrivacySettings(cx: Scope) -&gt; Element { unimplemented!() }
  905. </span>
  906. fn GlobalFallback(cx: Scope) -&gt; Element {
  907. render! {
  908. h1 { &quot;Error 404 - Page Not Found&quot; }
  909. }
  910. }
  911. fn SettingsFallback(cx: Scope) -&gt; Element {
  912. render! {
  913. h1 { &quot;Error 404 - Settings Not Found&quot; }
  914. }
  915. }
  916. fn App(cx: Scope) -&gt; Element {
  917. use_router(
  918. cx,
  919. &amp;|| RouterConfiguration {
  920. <span class="boring"> synchronous: true,
  921. </span><span class="boring"> history: Box::new(MemoryHistory::with_initial_path(&quot;/settings/invalid&quot;).unwrap()),
  922. </span> ..Default::default()
  923. },
  924. &amp;|| {
  925. Segment::empty()
  926. .fixed(&quot;settings&quot;, Route::content(comp(Settings)).nested(
  927. Segment::content(comp(GeneralSettings))
  928. .fixed(&quot;password&quot;, comp(PasswordSettings))
  929. .fixed(&quot;privacy&quot;, comp(PrivacySettings))
  930. .fallback(comp(SettingsFallback))
  931. .clear_fallback(true)
  932. ))
  933. .fallback(comp(GlobalFallback))
  934. }
  935. );
  936. render! {
  937. Outlet { }
  938. }
  939. }
  940. <span class="boring">
  941. </span><span class="boring">let mut vdom = VirtualDom::new(App);
  942. </span><span class="boring">vdom.rebuild();
  943. </span><span class="boring">assert_eq!(
  944. </span><span class="boring"> dioxus_ssr::render(&amp;vdom),
  945. </span><span class="boring"> &quot;&lt;h1&gt;Error 404 - Settings Not Found&lt;/h1&gt;&quot;
  946. </span><span class="boring">);
  947. </span><span class="boring">}
  948. </span></code></pre></pre>
  949. <div style="break-before: page; page-break-before: always;"></div><h1 id="multiple-components--redirects"><a class="header" href="#multiple-components--redirects">Multiple Components &amp; Redirects</a></h1>
  950. <h2 id="multiple-components"><a class="header" href="#multiple-components">Multiple Components</a></h2>
  951. <p>When creating complex apps we sometimes want to have multiple pieces of content
  952. side by side. The router allows us to do this. For more details see the section
  953. about <a href="features/routes/../outlets.html#named-outlets">named <code>Outlet</code>s</a>.</p>
  954. <h2 id="redirects"><a class="header" href="#redirects">Redirects</a></h2>
  955. <p>In some cases we may want to redirect our users to another page whenever they
  956. open a specific path. We can tell the router to do this when defining our
  957. routes.</p>
  958. <blockquote>
  959. <p>Redirects to external pages only work in certain conditions. For more details
  960. see the chapter about <a href="features/routes/../failures/external.html">external navigation failures</a>.</p>
  961. </blockquote>
  962. <p>In the following example we will redirect everybody from <code>/</code> and <code>/start</code> to
  963. <code>/home</code>.</p>
  964. <pre><pre class="playground"><code class="language-rust edition2021">
  965. <span class="boring">#![allow(unused)]
  966. </span><span class="boring">fn main() {
  967. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  968. </span><span class="boring">extern crate dioxus;
  969. </span>use dioxus::prelude::*;
  970. <span class="boring">extern crate dioxus_router;
  971. </span>use dioxus_router::{history::MemoryHistory, prelude::*};
  972. <span class="boring">extern crate dioxus_ssr;
  973. </span>
  974. fn Home(cx: Scope) -&gt; Element {
  975. render! {
  976. h1 { &quot;Home Page&quot; }
  977. }
  978. }
  979. fn App(cx: Scope) -&gt; Element {
  980. use_router(
  981. cx,
  982. &amp;|| RouterConfiguration {
  983. <span class="boring"> synchronous: true,
  984. </span><span class="boring"> history: Box::new(MemoryHistory::with_initial_path(&quot;/home&quot;).unwrap()),
  985. </span> ..Default::default()
  986. },
  987. &amp;|| {
  988. Segment::content(comp(Home))
  989. // notice that we use RouteContent::Redirect instead of
  990. // RouteContent::Content (which we have been using indirectly)
  991. .fixed(
  992. &quot;home&quot;,
  993. RouteContent::Redirect(NavigationTarget::Internal(&quot;/&quot;.into()))
  994. )
  995. .fixed(&quot;start&quot;, &quot;/&quot;) // short form
  996. });
  997. render! {
  998. Outlet { }
  999. }
  1000. }
  1001. <span class="boring">
  1002. </span><span class="boring">let mut vdom = VirtualDom::new(App);
  1003. </span><span class="boring">vdom.rebuild();
  1004. </span><span class="boring">let html = dioxus_ssr::render(&amp;vdom);
  1005. </span><span class="boring">assert_eq!(html, &quot;&lt;h1&gt;Home Page&lt;/h1&gt;&quot;);
  1006. </span><span class="boring">}
  1007. </span></code></pre></pre>
  1008. <div style="break-before: page; page-break-before: always;"></div><h1 id="outlets"><a class="header" href="#outlets">Outlets</a></h1>
  1009. <p><a href="https://docs.rs/dioxus-router/latest/dioxus_router/components/fn.Outlet.html"><code>Outlet</code></a>s tell the router where to render content. In the following example
  1010. the active routes content will be rendered within the <a href="https://docs.rs/dioxus-router/latest/dioxus_router/components/fn.Outlet.html"><code>Outlet</code></a>.</p>
  1011. <pre><pre class="playground"><code class="language-rust edition2021">
  1012. <span class="boring">#![allow(unused)]
  1013. </span><span class="boring">fn main() {
  1014. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  1015. </span><span class="boring">extern crate dioxus;
  1016. </span><span class="boring">use dioxus::prelude::*;
  1017. </span><span class="boring">extern crate dioxus_router;
  1018. </span><span class="boring">use dioxus_router::prelude::*;
  1019. </span><span class="boring">extern crate dioxus_ssr;
  1020. </span>
  1021. fn Index(cx: Scope) -&gt; Element {
  1022. render! {
  1023. h1 { &quot;Index&quot; }
  1024. }
  1025. }
  1026. fn App(cx: Scope) -&gt; Element {
  1027. use_router(
  1028. cx,
  1029. &amp;|| RouterConfiguration {
  1030. <span class="boring"> synchronous: true,
  1031. </span> ..Default::default()
  1032. },
  1033. &amp;|| Segment::content(comp(Index))
  1034. );
  1035. render! {
  1036. header { &quot;header&quot; }
  1037. Outlet { }
  1038. footer { &quot;footer&quot; }
  1039. }
  1040. }
  1041. <span class="boring">
  1042. </span><span class="boring">let mut vdom = VirtualDom::new(App);
  1043. </span><span class="boring">vdom.rebuild();
  1044. </span><span class="boring">let html = dioxus_ssr::render(&amp;vdom);
  1045. </span><span class="boring">assert_eq!(
  1046. </span><span class="boring"> html,
  1047. </span><span class="boring"> &quot;&lt;header&gt;header&lt;/header&gt;&lt;h1&gt;Index&lt;/h1&gt;&lt;footer&gt;footer&lt;/footer&gt;&quot;
  1048. </span><span class="boring">);
  1049. </span><span class="boring">}
  1050. </span></code></pre></pre>
  1051. <p>The example above will output the following HTML (line breaks added for
  1052. readability):</p>
  1053. <pre><code class="language-html">&lt;header&gt;
  1054. header
  1055. &lt;/header&gt;
  1056. &lt;h1&gt;
  1057. Index
  1058. &lt;/h1&gt;
  1059. &lt;footer&gt;
  1060. footer
  1061. &lt;/footer&gt;
  1062. </code></pre>
  1063. <h2 id="nested-outlets"><a class="header" href="#nested-outlets">Nested Outlets</a></h2>
  1064. <p>When using nested routes, we need to provide equally nested <a href="https://docs.rs/dioxus-router/latest/dioxus_router/components/fn.Outlet.html"><code>Outlet</code></a>s.</p>
  1065. <blockquote>
  1066. <p>Learn more about <a href="features/./routes/nested.html">nested routes</a> in their own chapter.</p>
  1067. </blockquote>
  1068. <h2 id="named-outlets"><a class="header" href="#named-outlets">Named Outlets</a></h2>
  1069. <p>When building complex apps, we often need to display multiple pieces of content
  1070. simultaneously. For example, we might have a sidebar that changes its content in
  1071. sync with the main part of the page.</p>
  1072. <p>When defining our routes, we can use <code>RouteContentMulti</code> instead of
  1073. <code>RouteContent::Component</code> (we've been using this through the <code>Into</code> trait) to
  1074. tell the router about our content.</p>
  1075. <p>We then can use a named <a href="https://docs.rs/dioxus-router/latest/dioxus_router/components/fn.Outlet.html"><code>Outlet</code></a> in our output, to tell the router where to
  1076. put the side content.</p>
  1077. <pre><pre class="playground"><code class="language-rust edition2021">
  1078. <span class="boring">#![allow(unused)]
  1079. </span><span class="boring">fn main() {
  1080. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  1081. </span><span class="boring">extern crate dioxus;
  1082. </span><span class="boring">use dioxus::prelude::*;
  1083. </span><span class="boring">extern crate dioxus_router;
  1084. </span><span class="boring">use dioxus_router::prelude::*;
  1085. </span><span class="boring">extern crate dioxus_ssr;
  1086. </span><span class="boring">
  1087. </span>
  1088. fn Main(cx: Scope) -&gt; Element {
  1089. render! {
  1090. main { &quot;Main Content&quot; }
  1091. }
  1092. }
  1093. struct AsideName;
  1094. fn Aside(cx: Scope) -&gt; Element {
  1095. render! {
  1096. aside { &quot;Side Content&quot; }
  1097. }
  1098. }
  1099. fn App(cx: Scope) -&gt; Element {
  1100. use_router(
  1101. cx,
  1102. &amp;|| RouterConfiguration {
  1103. <span class="boring"> synchronous: true,
  1104. </span> ..Default::default()
  1105. },
  1106. &amp;|| {
  1107. Segment::content(
  1108. multi(Some(comp(Main)))
  1109. .add_named::&lt;AsideName&gt;(comp(Aside))
  1110. )
  1111. }
  1112. );
  1113. render! {
  1114. Outlet { }
  1115. Outlet {
  1116. name: Name::of::&lt;AsideName&gt;()
  1117. }
  1118. }
  1119. }
  1120. <span class="boring">
  1121. </span><span class="boring">let mut vdom = VirtualDom::new(App);
  1122. </span><span class="boring">vdom.rebuild();
  1123. </span><span class="boring">let html = dioxus_ssr::render(&amp;vdom);
  1124. </span><span class="boring">assert_eq!(html, &quot;&lt;main&gt;Main Content&lt;/main&gt;&lt;aside&gt;Side Content&lt;/aside&gt;&quot;);
  1125. </span><span class="boring">}
  1126. </span></code></pre></pre>
  1127. <p>The example above will output the following HTML (line breaks added for
  1128. readability):</p>
  1129. <pre><code class="language-html">&lt;main&gt;
  1130. Main Content
  1131. &lt;/main&gt;
  1132. &lt;aside&gt;
  1133. Side Content
  1134. &lt;/aside&gt;
  1135. </code></pre>
  1136. <h2 id="outlet-depth-override"><a class="header" href="#outlet-depth-override">Outlet depth override</a></h2>
  1137. <p>When nesting <a href="https://docs.rs/dioxus-router/latest/dioxus_router/components/fn.Outlet.html"><code>Outlet</code></a>s, they communicate with each other. This allows the
  1138. nested <a href="https://docs.rs/dioxus-router/latest/dioxus_router/components/fn.Outlet.html"><code>Outlet</code></a> to render the content of the nested route.</p>
  1139. <p>We can override the detected value. Be careful when doing so, it is incredibly
  1140. easy to create an unterminated recursion. See below for an example of that.</p>
  1141. <pre><pre class="playground"><code class="language-rust edition2021">
  1142. <span class="boring">#![allow(unused)]
  1143. </span><span class="boring">fn main() {
  1144. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  1145. </span><span class="boring">extern crate dioxus;
  1146. </span><span class="boring">use dioxus::prelude::*;
  1147. </span><span class="boring">extern crate dioxus_router;
  1148. </span><span class="boring">use dioxus_router::{history::MemoryHistory, prelude::*};
  1149. </span><span class="boring">extern crate dioxus_ssr;
  1150. </span><span class="boring">
  1151. </span>fn RootContent(cx: Scope) -&gt; Element {
  1152. render! {
  1153. h1 { &quot;Root&quot; }
  1154. Outlet { }
  1155. }
  1156. }
  1157. fn NestedContent(cx: Scope) -&gt; Element {
  1158. render! {
  1159. h2 { &quot;Nested&quot; }
  1160. }
  1161. }
  1162. fn App(cx: Scope) -&gt; Element {
  1163. use_router(
  1164. cx,
  1165. &amp;|| RouterConfiguration {
  1166. <span class="boring"> synchronous: true,
  1167. </span><span class="boring"> history: Box::new(MemoryHistory::with_initial_path(&quot;/root&quot;).unwrap()),
  1168. </span> ..Default::default()
  1169. },
  1170. &amp;|| {
  1171. Segment::empty().fixed(
  1172. &quot;root&quot;,
  1173. Route::content(comp(RootContent)).nested(
  1174. Segment::content(comp(NestedContent))
  1175. )
  1176. )
  1177. }
  1178. );
  1179. render! {
  1180. Outlet {
  1181. depth: 1
  1182. }
  1183. }
  1184. }
  1185. <span class="boring">
  1186. </span><span class="boring">let mut vdom = VirtualDom::new(App);
  1187. </span><span class="boring">vdom.rebuild();
  1188. </span><span class="boring">let html = dioxus_ssr::render(&amp;vdom);
  1189. </span><span class="boring">assert_eq!(html, &quot;&lt;h2&gt;Nested&lt;/h2&gt;&quot;);
  1190. </span><span class="boring">}
  1191. </span></code></pre></pre>
  1192. <p>The example above will output the following HTML (line breaks added for
  1193. readability):</p>
  1194. <pre><code class="language-html">&lt;h2&gt;
  1195. Nested
  1196. &lt;/h2&gt;
  1197. </code></pre>
  1198. <h3 id="outlet-recursion"><a class="header" href="#outlet-recursion">Outlet recursion</a></h3>
  1199. <p>This code will create a crash due to an unterminated recursion using
  1200. <a href="https://docs.rs/dioxus-router/latest/dioxus_router/components/fn.Outlet.html"><code>Outlet</code></a>s.</p>
  1201. <pre><pre class="playground"><code class="language-rust no_run edition2021">
  1202. <span class="boring">#![allow(unused)]
  1203. </span><span class="boring">fn main() {
  1204. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  1205. </span><span class="boring">extern crate dioxus;
  1206. </span><span class="boring">use dioxus::prelude::*;
  1207. </span><span class="boring">extern crate dioxus_router;
  1208. </span><span class="boring">use dioxus_router::prelude::*;
  1209. </span><span class="boring">
  1210. </span>fn Content(cx: Scope) -&gt; Element {
  1211. render! {
  1212. h1 { &quot;Heyho!&quot; }
  1213. Outlet {
  1214. depth: 0,
  1215. }
  1216. }
  1217. }
  1218. fn App(cx: Scope) -&gt; Element {
  1219. use_router(cx, &amp;Default::default, &amp;|| Segment::content(comp(Content)));
  1220. render! {
  1221. Outlet { }
  1222. }
  1223. }
  1224. <span class="boring">}
  1225. </span></code></pre></pre>
  1226. <p>The <a href="https://docs.rs/dioxus-router/latest/dioxus_router/components/fn.Outlet.html"><code>Outlet</code></a> in the <code>App</code> component has no parent <a href="https://docs.rs/dioxus-router/latest/dioxus_router/components/fn.Outlet.html"><code>Outlet</code></a>, so its depth
  1227. will be <code>0</code>. When rendering for the path <code>/</code>, it therefore will render the
  1228. <code>Content</code> component.</p>
  1229. <p>The <code>Content</code> component will render an <code>h1</code> and an <a href="https://docs.rs/dioxus-router/latest/dioxus_router/components/fn.Outlet.html"><code>Outlet</code></a>. That <a href="https://docs.rs/dioxus-router/latest/dioxus_router/components/fn.Outlet.html"><code>OUtlet</code></a>
  1230. would usually have a depth of <code>1</code>, since it is a descendant of the <a href="https://docs.rs/dioxus-router/latest/dioxus_router/components/fn.Outlet.html"><code>Outlet</code></a> in
  1231. the <code>App</code> component. However, we override its depth to <code>0</code>, so it will render
  1232. the <code>Content</code> component.</p>
  1233. <p>That means the <code>Content</code> component will recurse until someone (e.g. the OS) puts
  1234. a stop to it.</p>
  1235. <div style="break-before: page; page-break-before: always;"></div><h1 id="links--navigation"><a class="header" href="#links--navigation">Links &amp; Navigation</a></h1>
  1236. <p>When we split our app into pages, we need to provide our users with a way to
  1237. navigate between them. On regular web pages we'd use an anchor element for that,
  1238. like this:</p>
  1239. <pre><code class="language-html">&lt;a href=&quot;/other&quot;&gt;Link to an other page&lt;/a&gt;
  1240. </code></pre>
  1241. <p>However, we cannot do that when using the router for two reasons:</p>
  1242. <ol>
  1243. <li>Anchor tags make the browser load a new page from the server. This takes a
  1244. lot of time, and it is much faster to let the router handle the navigation
  1245. client-side.</li>
  1246. <li>Navigation using anchor tags only works when the app is running inside a
  1247. browser. This means we cannot use them inside apps using Dioxus Desktop.</li>
  1248. </ol>
  1249. <p>To solve these problems, the router provides us with a <a href="https://docs.rs/dioxus-router/latest/dioxus_router/components/fn.Link.html"><code>Link</code></a> component we can
  1250. use like this:</p>
  1251. <pre><pre class="playground"><code class="language-rust no_run edition2021">
  1252. <span class="boring">#![allow(unused)]
  1253. </span><span class="boring">fn main() {
  1254. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  1255. </span><span class="boring">extern crate dioxus;
  1256. </span><span class="boring">use dioxus::prelude::*;
  1257. </span><span class="boring">extern crate dioxus_router;
  1258. </span><span class="boring">use dioxus_router::prelude::*;
  1259. </span>fn SomeComponent(cx: Scope) -&gt; Element {
  1260. render! {
  1261. Link {
  1262. target: NavigationTarget::Internal(String::from(&quot;/some/path&quot;)),
  1263. &quot;Link text&quot;
  1264. }
  1265. Link {
  1266. target: &quot;/some/path&quot;, // short form
  1267. &quot;Other link text&quot;
  1268. }
  1269. }
  1270. }
  1271. <span class="boring">}
  1272. </span></code></pre></pre>
  1273. <p>The <code>target</code> in the example above is similar to the <code>href</code> of a regular anchor
  1274. element. However, it tells the router more about what kind of navigation it
  1275. should perform:</p>
  1276. <ul>
  1277. <li>The example uses <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/navigation/enum.NavigationTarget.html#variant.Internal"><code>Internal</code></a>. We give it an arbitrary path that will be
  1278. merged with the current URL.</li>
  1279. <li><a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/navigation/enum.NavigationTarget.html#variant.Named"><code>Named</code></a> allows us to navigate within our app using predefined names.
  1280. See the chapter about <a href="features/navigation/./name.html">named navigation</a> for more details.</li>
  1281. <li><a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/navigation/enum.NavigationTarget.html#variant.External"><code>External</code></a> allows us to navigate to URLs outside of our app. See the
  1282. chapter about <a href="features/navigation/./external.html">external navigation</a> for more details.</li>
  1283. </ul>
  1284. <blockquote>
  1285. <p>The <a href="https://docs.rs/dioxus-router/latest/dioxus_router/components/fn.Link.html"><code>Link</code></a> accepts several props that modify its behavior. See the API docs
  1286. for more details.</p>
  1287. </blockquote>
  1288. <div style="break-before: page; page-break-before: always;"></div><h1 id="named-navigation"><a class="header" href="#named-navigation">Named Navigation</a></h1>
  1289. <p>When creating large applications, it can become difficult to keep track of all
  1290. routes and how to navigate to them. It also can be hard to find all links to
  1291. them, which makes it difficult to change paths.</p>
  1292. <p>To solve these problems, the router implements named navigation. When we define
  1293. our routes we can give them arbitrary, unique names (completely independent from
  1294. the path) and later ask the router to navigate to those names. The router will
  1295. automatically create the actual path to navigate to, even inserting required
  1296. parameters.</p>
  1297. <p><em>Named</em> navigation has a few advantages over <em>path-based</em> navigation:</p>
  1298. <ul>
  1299. <li>Links can be created without knowing the actual path.</li>
  1300. <li>It is much easier to find all links to a specific route.</li>
  1301. <li>The router knows what links are invalid (and will panic in debug builds).</li>
  1302. </ul>
  1303. <blockquote>
  1304. <p>When the router encounters an invalid link in a release build, it has to
  1305. handle that problem. You can hook into that process, to display a custom error
  1306. message. See the chapter about
  1307. <a href="features/navigation/../failures/named.html">named navigation failures</a>.</p>
  1308. </blockquote>
  1309. <blockquote>
  1310. <p>The router will automatically define the name <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/prelude/struct.RootIndex.html"><code>RootIndex</code></a> to refer to the
  1311. root index route (<code>/</code>).</p>
  1312. <p>It will also add other names (all of them are in the prelude module) in
  1313. certain conditions. None of these names can be used for app defined routes.</p>
  1314. </blockquote>
  1315. <h2 id="code-example-1"><a class="header" href="#code-example-1">Code Example</a></h2>
  1316. <pre><pre class="playground"><code class="language-rust edition2021">
  1317. <span class="boring">#![allow(unused)]
  1318. </span><span class="boring">fn main() {
  1319. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  1320. </span><span class="boring">extern crate dioxus;
  1321. </span>use dioxus::prelude::*;
  1322. <span class="boring">extern crate dioxus_router;
  1323. </span>use dioxus_router::prelude::*;
  1324. <span class="boring">extern crate dioxus_ssr;
  1325. </span>
  1326. // we define a unit struct which will serve as our name
  1327. struct TargetName;
  1328. fn Source(cx: Scope) -&gt; Element {
  1329. render! {
  1330. Link {
  1331. // instead of InternalTarget we use NamedTarget (via the `named` fn)
  1332. // we can use the returned value to add parameters or a query
  1333. target: named::&lt;TargetName&gt;().query(&quot;query&quot;),
  1334. &quot;Go to target&quot;
  1335. }
  1336. }
  1337. }
  1338. fn Target(cx: Scope) -&gt; Element {
  1339. render! {
  1340. h1 { &quot;Target&quot; }
  1341. }
  1342. }
  1343. fn App(cx: Scope) -&gt; Element {
  1344. use_router(
  1345. cx,
  1346. &amp;|| RouterConfiguration {
  1347. <span class="boring"> synchronous: true,
  1348. </span> ..Default::default()
  1349. },
  1350. &amp;|| {
  1351. Segment::content(comp(Source))
  1352. .fixed(
  1353. &quot;target_path&quot;,
  1354. Route::content(comp(Target)).name::&lt;TargetName&gt;()
  1355. )
  1356. }
  1357. );
  1358. render! {
  1359. Outlet { }
  1360. }
  1361. }
  1362. <span class="boring">
  1363. </span><span class="boring">let mut vdom = VirtualDom::new(App);
  1364. </span><span class="boring">vdom.rebuild();
  1365. </span><span class="boring">let html = dioxus_ssr::render(&amp;vdom);
  1366. </span><span class="boring">assert_eq!(
  1367. </span><span class="boring"> html,
  1368. </span><span class="boring"> format!(
  1369. </span><span class="boring"> &quot;&lt;a {attr1} {attr2}&gt;Go to target&lt;/a&gt;&quot;,
  1370. </span><span class="boring"> attr1 = r#&quot;href=&quot;/target_path?query&quot; dioxus-prevent-default=&quot;onclick&quot;&quot;#,
  1371. </span><span class="boring"> attr2 = r#&quot;class=&quot;&quot; id=&quot;&quot; rel=&quot;&quot; target=&quot;&quot;&quot;#
  1372. </span><span class="boring"> )
  1373. </span><span class="boring">)
  1374. </span><span class="boring">}
  1375. </span></code></pre></pre>
  1376. <h2 id="check-if-a-name-is-present"><a class="header" href="#check-if-a-name-is-present">Check if a name is present</a></h2>
  1377. <p>You can check if a specific name is present for the current route. This works
  1378. similar to getting the value of a <a href="features/navigation/../routes/parameter.html">parameter route</a> and
  1379. the same restrictions apply.</p>
  1380. <pre><pre class="playground"><code class="language-rust no_run edition2021">
  1381. <span class="boring">#![allow(unused)]
  1382. </span><span class="boring">fn main() {
  1383. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  1384. </span><span class="boring">extern crate dioxus;
  1385. </span>use dioxus::prelude::*;
  1386. <span class="boring">extern crate dioxus_router;
  1387. </span>use dioxus_router::prelude::*;
  1388. struct SomeName;
  1389. fn Content(cx: Scope) -&gt; Element {
  1390. let route = use_route(cx).expect(&quot;needs to be in router&quot;);
  1391. if route.is_at(&amp;named::&lt;SomeName&gt;(), false) {
  1392. // do something
  1393. }
  1394. // ...
  1395. <span class="boring"> todo!()
  1396. </span>}
  1397. <span class="boring">}
  1398. </span></code></pre></pre>
  1399. <div style="break-before: page; page-break-before: always;"></div><h1 id="external-navigation"><a class="header" href="#external-navigation">External Navigation</a></h1>
  1400. <p>In modern apps, and especially on the web, we often want to send our users to an
  1401. other website. <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/navigation/enum.NavigationTarget.html#variant.External"><code>External</code></a> allows us to make a <a href="https://docs.rs/dioxus-router/latest/dioxus_router/components/fn.Link.html"><code>Link</code></a> navigate to an
  1402. external page.</p>
  1403. <blockquote>
  1404. <p>You might already now about
  1405. <a href="features/navigation/../failures/external.html">external navigation failures</a>. The <a href="https://docs.rs/dioxus-router/latest/dioxus_router/components/fn.Link.html"><code>Link</code></a>
  1406. component doesn't rely on the code path where those originate. Therefore a
  1407. <a href="https://docs.rs/dioxus-router/latest/dioxus_router/components/fn.Link.html"><code>Link</code></a> will never trigger an external navigation failure.</p>
  1408. </blockquote>
  1409. <p>Strictly speaking, a <a href="https://docs.rs/dioxus-router/latest/dioxus_router/components/fn.Link.html"><code>Link</code></a> is not necessary for navigating to external
  1410. targets, since by definition the router cannot handle them internally. However,
  1411. the <a href="https://docs.rs/dioxus-router/latest/dioxus_router/components/fn.Link.html"><code>Link</code></a> component is more convenient to use, as it automatically sets the
  1412. <code>rel</code> attribute for the link, when the target is external.</p>
  1413. <h2 id="code-example-2"><a class="header" href="#code-example-2">Code Example</a></h2>
  1414. <pre><pre class="playground"><code class="language-rust edition2021">
  1415. <span class="boring">#![allow(unused)]
  1416. </span><span class="boring">fn main() {
  1417. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  1418. </span><span class="boring">extern crate dioxus;
  1419. </span>use dioxus::prelude::*;
  1420. <span class="boring">extern crate dioxus_router;
  1421. </span>use dioxus_router::prelude::*;
  1422. <span class="boring">extern crate dioxus_ssr;
  1423. </span>
  1424. fn App(cx: Scope) -&gt; Element {
  1425. use_router(
  1426. cx,
  1427. &amp;|| RouterConfiguration {
  1428. <span class="boring"> synchronous: true,
  1429. </span> ..Default::default()
  1430. },
  1431. &amp;|| Segment::empty()
  1432. );
  1433. render! {
  1434. // links need to be inside a router, even if they navigate to an
  1435. // external page
  1436. Link {
  1437. target: NavigationTarget::External(&quot;https://dioxuslabs.com/&quot;.into()),
  1438. &quot;Go to the dioxus home page&quot;
  1439. }
  1440. Link {
  1441. target: &quot;https://dioxuslabs.com/&quot;, // short form
  1442. &quot;Go to the dioxus home page 2&quot;
  1443. }
  1444. }
  1445. }
  1446. <span class="boring">
  1447. </span><span class="boring">let mut vdom = VirtualDom::new(App);
  1448. </span><span class="boring">vdom.rebuild();
  1449. </span><span class="boring">let html = dioxus_ssr::render(&amp;vdom);
  1450. </span><span class="boring">assert_eq!(
  1451. </span><span class="boring"> html,
  1452. </span><span class="boring"> format!(
  1453. </span><span class="boring"> &quot;&lt;a {attr1} {attr2}&gt;{text}&lt;/a&gt;&lt;a {attr1} {attr2}&gt;{text} 2&lt;/a&gt;&quot;,
  1454. </span><span class="boring"> attr1 = r#&quot;href=&quot;https://dioxuslabs.com/&quot; dioxus-prevent-default=&quot;&quot;&quot;#,
  1455. </span><span class="boring"> attr2 = r#&quot;class=&quot;&quot; id=&quot;&quot; rel=&quot;noopener noreferrer&quot; target=&quot;&quot;&quot;#,
  1456. </span><span class="boring"> text = &quot;Go to the dioxus home page&quot;
  1457. </span><span class="boring"> )
  1458. </span><span class="boring">)
  1459. </span><span class="boring">}
  1460. </span></code></pre></pre>
  1461. <blockquote>
  1462. <p>Note that the short form for an [<code>ExternalTarget</code>] looks like the short form
  1463. for an [<code>InternalTarget</code>]. The router will create an [<code>ExternalTarget</code>] only
  1464. if the URL is absolute.</p>
  1465. </blockquote>
  1466. <div style="break-before: page; page-break-before: always;"></div><h1 id="programmatic-navigation"><a class="header" href="#programmatic-navigation">Programmatic Navigation</a></h1>
  1467. <p>Sometimes we want our application to navigate to another page without having the
  1468. user click on a link. This is called programmatic navigation.</p>
  1469. <h2 id="acquiring-a-navigator"><a class="header" href="#acquiring-a-navigator">Acquiring a <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/hooks/struct.Navigator.html"><code>Navigator</code></a></a></h2>
  1470. <p>To use programmatic navigation, we first have to acquire a <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/hooks/struct.Navigator.html"><code>Navigator</code></a>. For
  1471. that purpose we can use the <a href="https://docs.rs/dioxus-router/latest/dioxus_router/hooks/fn.use_navigate.html"><code>use_navigate</code></a> hook.</p>
  1472. <pre><pre class="playground"><code class="language-rust no_run edition2021">
  1473. <span class="boring">#![allow(unused)]
  1474. </span><span class="boring">fn main() {
  1475. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  1476. </span><span class="boring">extern crate dioxus;
  1477. </span>use dioxus::prelude::*;
  1478. <span class="boring">extern crate dioxus_router;
  1479. </span>use dioxus_router::prelude::*;
  1480. fn Content(cx: Scope) -&gt; Element {
  1481. let nav = use_navigate(cx).expect(&quot;called inside a router&quot;);
  1482. // ...
  1483. <span class="boring"> unimplemented!()
  1484. </span>}
  1485. <span class="boring">}
  1486. </span></code></pre></pre>
  1487. <h2 id="triggering-a-navigation"><a class="header" href="#triggering-a-navigation">Triggering a Navigation</a></h2>
  1488. <p>We can use the <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/hooks/struct.Navigator.html"><code>Navigator</code></a> to trigger four different kinds of navigation:</p>
  1489. <ul>
  1490. <li><code>push</code> will navigate to the target. It works like a regular anchor tag.</li>
  1491. <li><code>replace</code> works like <code>push</code>, except that it replaces the current history entry
  1492. instead of adding a new one. This means the prior page cannot be restored with
  1493. the browsers back button.</li>
  1494. <li><code>Go back</code> works like the browsers back button.</li>
  1495. <li><code>Go forward</code> works like the browsers forward button (the opposite of the back
  1496. button).</li>
  1497. </ul>
  1498. <pre><pre class="playground"><code class="language-rust no_run edition2021">
  1499. <span class="boring">#![allow(unused)]
  1500. </span><span class="boring">fn main() {
  1501. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  1502. </span><span class="boring">extern crate dioxus;
  1503. </span><span class="boring">use dioxus::prelude::*;
  1504. </span><span class="boring">extern crate dioxus_router;
  1505. </span><span class="boring">use dioxus_router::prelude::*;
  1506. </span><span class="boring">
  1507. </span>fn Content(cx: Scope) -&gt; Element {
  1508. let nav = use_navigate(cx).expect(&quot;called inside a router&quot;);
  1509. // push
  1510. nav.push(&quot;/target&quot;);
  1511. // replace
  1512. nav.replace(&quot;/target&quot;);
  1513. // go back
  1514. nav.go_back();
  1515. // go forward
  1516. nav.go_forward();
  1517. // ...
  1518. <span class="boring"> unimplemented!()
  1519. </span>}
  1520. <span class="boring">}
  1521. </span></code></pre></pre>
  1522. <p>You might have noticed that, like <a href="https://docs.rs/dioxus-router/latest/dioxus_router/components/fn.Link.html"><code>Link</code></a>, the <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/hooks/struct.Navigator.html"><code>Navigator</code></a>s <code>push</code> and
  1523. <code>replace</code> functions take a <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/navigation/enum.NavigationTarget.html"><code>NavigationTarget</code></a>. This means we can use
  1524. <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/navigation/enum.NavigationTarget.html#variant.Internal"><code>Internal</code></a>, <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/navigation/enum.NavigationTarget.html#variant.Named"><code>Named</code></a> and <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/navigation/enum.NavigationTarget.html#variant.External"><code>External</code></a>.</p>
  1525. <h2 id="external-navigation-targets"><a class="header" href="#external-navigation-targets">External Navigation Targets</a></h2>
  1526. <p>Unlike a <a href="https://docs.rs/dioxus-router/latest/dioxus_router/components/fn.Link.html"><code>Link</code></a>, the <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/hooks/struct.Navigator.html"><code>Navigator</code></a> cannot rely on the browser (or webview) to
  1527. handle navigation to external targets via a generated anchor element.</p>
  1528. <p>This means, that under certain conditions, navigation to external targets can
  1529. fail. See the chapter about
  1530. <a href="features/navigation/../failures/external.html">external navigation failures</a> for more details.</p>
  1531. <div style="break-before: page; page-break-before: always;"></div><h1 id="query"><a class="header" href="#query">Query</a></h1>
  1532. <p>Some apps use the query part of the URL to encode information. The router allows
  1533. you to easily access the query, as well as set it when navigating.</p>
  1534. <h2 id="accessing-the-query"><a class="header" href="#accessing-the-query">Accessing the query</a></h2>
  1535. <p>The <a href="https://docs.rs/dioxus-router/latest/dioxus_router/hooks/fn.use_route.html"><code>use_route</code></a> hook allows us to access the current query in two ways. The
  1536. returned <code>struct</code> contains a <code>query</code> field, that contains the query (without the
  1537. leading <code>?</code>).</p>
  1538. <pre><pre class="playground"><code class="language-rust no_run edition2021">
  1539. <span class="boring">#![allow(unused)]
  1540. </span><span class="boring">fn main() {
  1541. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  1542. </span><span class="boring">extern crate dioxus;
  1543. </span>use dioxus::prelude::*;
  1544. <span class="boring">extern crate dioxus_router;
  1545. </span>use dioxus_router::prelude::*;
  1546. fn SomeComponent(cx: Scope) -&gt; Element {
  1547. let route = use_route(cx).expect(&quot;nested in Router&quot;);
  1548. let query = route.query.clone().unwrap();
  1549. // ...
  1550. <span class="boring"> unimplemented!()
  1551. </span>}
  1552. <span class="boring">}
  1553. </span></code></pre></pre>
  1554. <h2 id="setting-the-query"><a class="header" href="#setting-the-query">Setting the query</a></h2>
  1555. <p>When navigating we can tell the router to change the query. However, the method
  1556. we use to do this is very different, depending on how we specify our target.</p>
  1557. <h3 id="internal-and-external"><a class="header" href="#internal-and-external"><a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/navigation/enum.NavigationTarget.html#variant.Internal"><code>Internal</code></a> and <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/navigation/enum.NavigationTarget.html#variant.External"><code>External</code></a></a></h3>
  1558. <p>When using <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/navigation/enum.NavigationTarget.html#variant.Internal"><code>Internal</code></a> or <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/navigation/enum.NavigationTarget.html#variant.External"><code>External</code></a> we have to append our query manually.</p>
  1559. <pre><pre class="playground"><code class="language-rust no_run edition2021">
  1560. <span class="boring">#![allow(unused)]
  1561. </span><span class="boring">fn main() {
  1562. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  1563. </span><span class="boring">extern crate dioxus;
  1564. </span><span class="boring">use dioxus::prelude::*;
  1565. </span><span class="boring">extern crate dioxus_router;
  1566. </span><span class="boring">use dioxus_router::prelude::*;
  1567. </span><span class="boring">
  1568. </span>fn SomeComponent(cx: Scope) -&gt; Element {
  1569. render! {
  1570. Link {
  1571. target: NavigationTarget::Internal(&quot;/some/path?query=yes&quot;.into()),
  1572. &quot;Internal target&quot;
  1573. }
  1574. Link {
  1575. target: NavigationTarget::External(&quot;https://dioxuslab.com?query=yes&quot;.into()),
  1576. &quot;External target&quot;
  1577. }
  1578. }
  1579. }
  1580. <span class="boring">}
  1581. </span></code></pre></pre>
  1582. <h3 id="named"><a class="header" href="#named"><a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/navigation/enum.NavigationTarget.html#variant.Named"><code>Named</code></a></a></h3>
  1583. <p>When using <a href="features/./navigation/name.html">named navigation</a> we can pass the query via
  1584. a function.</p>
  1585. <pre><pre class="playground"><code class="language-rust no_run edition2021">
  1586. <span class="boring">#![allow(unused)]
  1587. </span><span class="boring">fn main() {
  1588. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  1589. </span><span class="boring">extern crate dioxus;
  1590. </span><span class="boring">use dioxus::prelude::*;
  1591. </span><span class="boring">extern crate dioxus_router;
  1592. </span><span class="boring">use dioxus_router::prelude::*;
  1593. </span><span class="boring">struct Target;
  1594. </span><span class="boring">
  1595. </span>fn SomeComponent(cx: Scope) -&gt; Element {
  1596. render! {
  1597. Link {
  1598. target: named::&lt;Target&gt;().query(&quot;query=yes&quot;),
  1599. &quot;Query String&quot;
  1600. }
  1601. Link {
  1602. target: named::&lt;Target&gt;().query(vec![(&quot;query&quot;, &quot;yes&quot;)]),
  1603. &quot;Query Vec&quot;
  1604. }
  1605. }
  1606. }
  1607. <span class="boring">}
  1608. </span></code></pre></pre>
  1609. <div style="break-before: page; page-break-before: always;"></div><h1 id="navigation-failures"><a class="header" href="#navigation-failures">Navigation Failures</a></h1>
  1610. <p>Some specific operations can cause a failure within router operations. The
  1611. subchapters contain information on how the router lets us handle such failures.</p>
  1612. <div style="break-before: page; page-break-before: always;"></div><h1 id="named-navigation-failure"><a class="header" href="#named-navigation-failure">Named Navigation Failure</a></h1>
  1613. <p>When using <a href="features/failures/../navigation/name.html">named navigation</a>, the router runs into a
  1614. problem under these circumstances:</p>
  1615. <ol>
  1616. <li>The name we try to navigate to is not contained within our routes.</li>
  1617. <li>The route we navigate to requires a parameter that we don't provide when
  1618. triggering the navigation.</li>
  1619. </ol>
  1620. <blockquote>
  1621. <p>Users cannot directly interact with named navigation. If a named navigation
  1622. failure occurs, your app (or the router) has a bug.</p>
  1623. </blockquote>
  1624. <p>The router reacts to this problem differently, depending on our apps build kind.</p>
  1625. <h2 id="debug"><a class="header" href="#debug">Debug</a></h2>
  1626. <p>When running a debug build, the router will <code>panic</code> whenever it encounters an
  1627. invalid navigation. This ensures that we notice these problems when we are
  1628. testing our application.</p>
  1629. <h2 id="release"><a class="header" href="#release">Release</a></h2>
  1630. <p>When running a release build, the router can't just <code>panic</code>, as that would be a
  1631. horrible user experience. Instead, it changes to show some fallback content.</p>
  1632. <blockquote>
  1633. <p>You can detect if the router is in the named navigation failure handling state
  1634. by <a href="features/failures/../navigation/name.html#check-if-a-name-is-present">checking</a> if the
  1635. <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/prelude/struct.FailureNamedNavigation.html"><code>FailureNamedNavigation</code></a> name is present.</p>
  1636. </blockquote>
  1637. <p>The default fallback explains to the user that an error occurred and asks them
  1638. to report the bug to the app developer.</p>
  1639. <p>You can override it by setting the <code>failure_named_navigation</code> value of the
  1640. <a href="https://docs.rs/dioxus-router/latest/dioxus_router/hooks/struct.RouterConfiguration.html"><code>RouterConfiguration</code></a>.</p>
  1641. <pre><pre class="playground"><code class="language-rust no_run edition2021">
  1642. <span class="boring">#![allow(unused)]
  1643. </span><span class="boring">fn main() {
  1644. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  1645. </span><span class="boring">extern crate dioxus;
  1646. </span><span class="boring">use dioxus::prelude::*;
  1647. </span><span class="boring">extern crate dioxus_router;
  1648. </span><span class="boring">use dioxus_router::prelude::*;
  1649. </span>fn NamedNavigationFallback(cx: Scope) -&gt; Element {
  1650. render! {
  1651. h1 { &quot;Named navigation failure!&quot; }
  1652. }
  1653. }
  1654. fn App(cx: Scope) -&gt; Element {
  1655. use_router(
  1656. cx,
  1657. &amp;|| RouterConfiguration {
  1658. failure_named_navigation: comp(NamedNavigationFallback),
  1659. ..Default::default()
  1660. },
  1661. &amp;|| Segment::empty()
  1662. );
  1663. render! {
  1664. Outlet { }
  1665. }
  1666. }
  1667. <span class="boring">}
  1668. </span></code></pre></pre>
  1669. <div style="break-before: page; page-break-before: always;"></div><h1 id="external-navigation-failure"><a class="header" href="#external-navigation-failure">External Navigation Failure</a></h1>
  1670. <blockquote>
  1671. <p>This section doesn't apply when specifying a <code>target</code> on a <a href="https://docs.rs/dioxus-router/latest/dioxus_router/components/fn.Link.html"><code>Link</code></a>. See the
  1672. chapter about <a href="features/failures/../navigation/external.html">external navigation</a> for more
  1673. details.</p>
  1674. </blockquote>
  1675. <p>When we ask the router to navigate to an external target, either through
  1676. <a href="features/failures/../navigation/programmatic.html">programmatic navigation</a> or a
  1677. <a href="features/failures/../routes/multiple-and-redirect.html#redirects">redirect</a> the router needs to
  1678. navigate to an external target without being able to rely on an anchor element.</p>
  1679. <p>This will only work in the browser, when using either <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/history/struct.WebHistory.html"><code>WebHistory</code></a> or
  1680. <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/history/struct.WebHashHistory.html"><code>WebHashHistory</code></a>.</p>
  1681. <h2 id="failure-handling"><a class="header" href="#failure-handling">Failure handling</a></h2>
  1682. <p>When the router encounters an external navigation it cannot fulfill, it changes
  1683. the path to <code>/</code> and shows some fallback content.</p>
  1684. <blockquote>
  1685. <p>You can detect if the router is in the external navigation failure handling
  1686. state by <a href="features/failures/../navigation/name.html#check-if-a-name-is-present">checking</a> if the
  1687. <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/prelude/struct.FailureExternalNavigation.html"><code>FailureExternalNavigation</code></a> name is present.</p>
  1688. </blockquote>
  1689. <p>The default fallback explains to the user that the navigation was unsuccessful
  1690. and provides them with a <a href="https://docs.rs/dioxus-router/latest/dioxus_router/components/fn.Link.html"><code>Link</code></a> to fulfill it manually. It also allows them to
  1691. go back to the previous page.</p>
  1692. <p>You can override it by setting the <code>failure_external_navigation</code> value of the
  1693. <a href="https://docs.rs/dioxus-router/latest/dioxus_router/hooks/struct.RouterConfiguration.html"><code>RouterConfiguration</code></a>. The external URL will be provided via the
  1694. <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/prelude/struct.FailureExternalNavigation.html"><code>FailureExternalNavigation</code></a> parameter.</p>
  1695. <pre><pre class="playground"><code class="language-rust no_run edition2021">
  1696. <span class="boring">#![allow(unused)]
  1697. </span><span class="boring">fn main() {
  1698. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  1699. </span><span class="boring">extern crate dioxus;
  1700. </span><span class="boring">use dioxus::prelude::*;
  1701. </span><span class="boring">extern crate dioxus_router;
  1702. </span><span class="boring">use dioxus_router::prelude::*;
  1703. </span>fn ExternalNavigationFallback(cx: Scope) -&gt; Element {
  1704. let route = use_route(cx).expect(&quot;is nested within a Router component&quot;);
  1705. let url = route
  1706. .parameter::&lt;FailureExternalNavigation&gt;()
  1707. .unwrap_or_default();
  1708. render! {
  1709. h1 { &quot;External navigation failure!&quot; }
  1710. Link {
  1711. target: url,
  1712. &quot;Go to external site&quot;
  1713. }
  1714. }
  1715. }
  1716. fn App(cx: Scope) -&gt; Element {
  1717. use_router(
  1718. cx,
  1719. &amp;|| RouterConfiguration {
  1720. failure_external_navigation: comp(ExternalNavigationFallback),
  1721. ..Default::default()
  1722. },
  1723. &amp;|| Segment::empty()
  1724. );
  1725. render! {
  1726. Outlet { }
  1727. }
  1728. }
  1729. <span class="boring">}
  1730. </span></code></pre></pre>
  1731. <div style="break-before: page; page-break-before: always;"></div><h1 id="redirection-limit-failure"><a class="header" href="#redirection-limit-failure">Redirection Limit Failure</a></h1>
  1732. <p>The router enforces a limit of 25 redirects during a single routing navigation.
  1733. This is done to prevent infinite loops. If your app breaches that limit, you
  1734. should reorganize its routes to reduce the number of redirects.</p>
  1735. <blockquote>
  1736. <p>Users cannot trigger a redirection. If the redirection limit is breached, your
  1737. app (or the router) has a bug.</p>
  1738. </blockquote>
  1739. <blockquote>
  1740. <p>The <a href="features/failures/../routing-update-callback.html"><code>on_update</code></a> callback doesn't count
  1741. towards the limit, and resets it. You may have 25 redirects, then add an other
  1742. one via the callback, and then have another 25.</p>
  1743. </blockquote>
  1744. <p>The router reacts to a breach differently, depending on our apps build kind.</p>
  1745. <h2 id="debug-1"><a class="header" href="#debug-1">Debug</a></h2>
  1746. <p>When running a debug build, the router will <code>panic</code> whenever the redirecion
  1747. limit is breached. This ensures that we notice these problems when we are
  1748. testing our application.</p>
  1749. <h2 id="release-1"><a class="header" href="#release-1">Release</a></h2>
  1750. <p>When running a release build, the router can't just <code>panic</code>, as that would be a
  1751. horrible user experience. Instead, it changes to show some fallback content.</p>
  1752. <blockquote>
  1753. <p>You can detect if the router is in the redirection limit failure handling
  1754. state by <a href="features/failures/../navigation/name.html#check-if-a-name-is-present">checking</a> if the
  1755. <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/prelude/struct.FailureRedirectionLimit.html"><code>FailureRedirectionLimit</code></a> name is present.</p>
  1756. </blockquote>
  1757. <p>The default fallback explains to the user that an error occurred and asks them
  1758. to report the bug to the app developer.</p>
  1759. <p>You can override it by setting the <code>failure_redirection_limit</code> value of the
  1760. <a href="https://docs.rs/dioxus-router/latest/dioxus_router/hooks/struct.RouterConfiguration.html"><code>RouterConfiguration</code></a>.</p>
  1761. <pre><pre class="playground"><code class="language-rust no_run edition2021">
  1762. <span class="boring">#![allow(unused)]
  1763. </span><span class="boring">fn main() {
  1764. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  1765. </span><span class="boring">extern crate dioxus;
  1766. </span><span class="boring">use dioxus::prelude::*;
  1767. </span><span class="boring">extern crate dioxus_router;
  1768. </span><span class="boring">use dioxus_router::prelude::*;
  1769. </span>fn RedirectionLimitFallback(cx: Scope) -&gt; Element {
  1770. render! {
  1771. h1 { &quot;Redirection limit breached!&quot; }
  1772. }
  1773. }
  1774. fn App(cx: Scope) -&gt; Element {
  1775. use_router(
  1776. cx,
  1777. &amp;|| RouterConfiguration {
  1778. failure_redirection_limit: comp(RedirectionLimitFallback),
  1779. ..Default::default()
  1780. },
  1781. &amp;|| Segment::empty()
  1782. );
  1783. render! {
  1784. Outlet { }
  1785. }
  1786. }
  1787. <span class="boring">}
  1788. </span></code></pre></pre>
  1789. <div style="break-before: page; page-break-before: always;"></div><h1 id="history-providers"><a class="header" href="#history-providers">History Providers</a></h1>
  1790. <p>In order to provide the ability to traverse the navigation history, the router
  1791. uses <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/history/trait.HistoryProvider.html"><code>HistoryProvider</code></a>s. Those implement the actual back-and-forth
  1792. functionality.</p>
  1793. <p>The router provides five <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/history/trait.HistoryProvider.html"><code>HistoryProvider</code></a>s, but you can also create your own.
  1794. The five default implementations are:</p>
  1795. <ul>
  1796. <li>The <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/history/struct.MemoryHistory.html"><code>MemoryHistory</code></a> is a custom implementation that works in memory.</li>
  1797. <li>The <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/history/struct.WebHistory.html"><code>WebHistory</code></a> integrates with the browsers URL.</li>
  1798. <li>The <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/history/struct.WebHashHistory.html"><code>WebHashHistory</code></a> also integrates with the browser, but uses the fragment
  1799. part of the URL.</li>
  1800. </ul>
  1801. <p>By default the router uses the <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/history/struct.MemoryHistory.html"><code>MemoryHistory</code></a>. It might be changed to use
  1802. <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/history/struct.WebHistory.html"><code>WebHistory</code></a> when the <code>web</code> feature is active, but that is not guaranteed.</p>
  1803. <p>You can override the default history:</p>
  1804. <pre><pre class="playground"><code class="language-rust no_run edition2021">
  1805. <span class="boring">#![allow(unused)]
  1806. </span><span class="boring">fn main() {
  1807. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  1808. </span><span class="boring">extern crate dioxus;
  1809. </span>use dioxus::prelude::*;
  1810. <span class="boring">extern crate dioxus_router;
  1811. </span>use dioxus_router::{prelude::*, history::WebHashHistory};
  1812. fn App(cx: Scope) -&gt; Element {
  1813. use_router(
  1814. cx,
  1815. &amp;|| RouterConfiguration {
  1816. history: Box::new(WebHashHistory::new(true)),
  1817. ..Default::default()
  1818. },
  1819. &amp;|| Segment::empty()
  1820. );
  1821. render! {
  1822. Outlet { }
  1823. }
  1824. }
  1825. <span class="boring">}
  1826. </span></code></pre></pre>
  1827. <div style="break-before: page; page-break-before: always;"></div><h1 id="history-buttons"><a class="header" href="#history-buttons">History Buttons</a></h1>
  1828. <p>Some platforms, like web browsers, provide users with an easy way to navigate
  1829. through an apps history. They have UI elements or integrate with the OS.</p>
  1830. <p>However, native platforms usually don't provide such amenities, which means that
  1831. apps wanting users to have access to them, need to implement them. For this
  1832. reason the router comes with two components, which emulate a browsers back and
  1833. forward buttons:</p>
  1834. <ul>
  1835. <li><a href="https://docs.rs/dioxus-router/latest/dioxus_router/components/fn.GoBackButton.html"><code>GoBackButton</code></a></li>
  1836. <li><a href="https://docs.rs/dioxus-router/latest/dioxus_router/components/fn.GoForwardButton.html"><code>GoForwardButton</code></a></li>
  1837. </ul>
  1838. <blockquote>
  1839. <p>If you want to navigate through the history programmatically, take a look at
  1840. <a href="features/./navigation/programmatic.html"><code>programmatic navigation</code></a>.</p>
  1841. </blockquote>
  1842. <pre><pre class="playground"><code class="language-rust no_run edition2021">
  1843. <span class="boring">#![allow(unused)]
  1844. </span><span class="boring">fn main() {
  1845. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  1846. </span><span class="boring">extern crate dioxus;
  1847. </span>use dioxus::prelude::*;
  1848. <span class="boring">extern crate dioxus_router;
  1849. </span>use dioxus_router::prelude::*;
  1850. fn HistoryNavigation(cx: Scope) -&gt; Element {
  1851. render! {
  1852. GoBackButton {
  1853. &quot;Back to the Past&quot;
  1854. }
  1855. GoForwardButton {
  1856. &quot;Back to the Future&quot; /* You see what I did there? 😉 */
  1857. }
  1858. }
  1859. }
  1860. <span class="boring">}
  1861. </span></code></pre></pre>
  1862. <p>As you might know, browsers usually disable the back and forward buttons if
  1863. there is no history to navigate to. The routers history buttons try to do that
  1864. too, but depending on the <a href="features/./history-providers.html">history provider</a> that might not be possible.</p>
  1865. <p>Importantly, neither <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/history/struct.WebHistory.html"><code>WebHistory</code></a> nor <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/history/struct.WebHashHistory.html"><code>WebHashHistory</code></a> support that feature.
  1866. This is due to limitations of the browser History API.</p>
  1867. <p>However, in both cases the router will just ignore button presses, if there is
  1868. no history to navigate to.</p>
  1869. <p>Also, when using <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/history/struct.WebHistory.html"><code>WebHistory</code></a> or <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/history/struct.WebHashHistory.html"><code>WebHashHistory</code></a>, the history buttons might
  1870. navigate a user to a history entry outside your app.</p>
  1871. <div style="break-before: page; page-break-before: always;"></div><h1 id="sitemap-generation"><a class="header" href="#sitemap-generation">Sitemap Generation</a></h1>
  1872. <p>If you need a list of all routes you have defined (e.g. for statically
  1873. generating all pages), Dioxus Router provides functions to extract that
  1874. information from a <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/routes/struct.Segment.html"><code>Segment</code></a>.</p>
  1875. <h2 id="preparing-an-app"><a class="header" href="#preparing-an-app">Preparing an app</a></h2>
  1876. <p>We will start by preparing an app with some routes like we normally would.</p>
  1877. <pre><pre class="playground"><code class="language-rust edition2021">
  1878. <span class="boring">#![allow(unused)]
  1879. </span><span class="boring">fn main() {
  1880. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  1881. </span><span class="boring">extern crate dioxus;
  1882. </span>use dioxus::prelude::*;
  1883. <span class="boring">extern crate dioxus_router;
  1884. </span>use dioxus_router::{history::MemoryHistory, prelude::*};
  1885. <span class="boring">extern crate dioxus_ssr;
  1886. </span>
  1887. fn Home(cx: Scope) -&gt; Element {
  1888. render! {
  1889. h1 { &quot;Home&quot; }
  1890. }
  1891. }
  1892. fn Fixed(cx: Scope) -&gt; Element {
  1893. render! {
  1894. h1 { &quot;Fixed&quot; }
  1895. Outlet { }
  1896. }
  1897. }
  1898. fn Nested(cx: Scope) -&gt; Element {
  1899. render! {
  1900. h2 { &quot;Nested&quot; }
  1901. }
  1902. }
  1903. struct ParameterName;
  1904. fn Parameter(cx: Scope) -&gt; Element {
  1905. let route = use_route(cx).unwrap();
  1906. let param = route.parameter::&lt;ParameterName&gt;().unwrap_or_default();
  1907. render! {
  1908. h1 { &quot;Parameter: {param}&quot; }
  1909. }
  1910. }
  1911. fn App(cx: Scope) -&gt; Element {
  1912. use_router(
  1913. cx,
  1914. &amp;|| RouterConfiguration {
  1915. <span class="boring"> synchronous: true,
  1916. </span> history: Box::new(MemoryHistory::with_initial_path(&quot;/fixed/nested&quot;).unwrap()),
  1917. ..Default::default()
  1918. },
  1919. &amp;|| {
  1920. Segment::content(comp(Home))
  1921. .fixed(
  1922. &quot;fixed&quot;,
  1923. Route::content(comp(Fixed)).nested(
  1924. Segment::empty().fixed(&quot;nested&quot;, comp(Nested))
  1925. )
  1926. )
  1927. .catch_all((comp(Parameter), ParameterName { }))
  1928. }
  1929. );
  1930. render! {
  1931. Outlet { }
  1932. }
  1933. }
  1934. <span class="boring">
  1935. </span><span class="boring">let mut vdom = VirtualDom::new(App);
  1936. </span><span class="boring">vdom.rebuild();
  1937. </span><span class="boring">assert_eq!(dioxus_ssr::render(&amp;mut vdom), &quot;&lt;h1&gt;Fixed&lt;/h1&gt;&lt;h2&gt;Nested&lt;/h2&gt;&quot;);
  1938. </span><span class="boring">}
  1939. </span></code></pre></pre>
  1940. <h2 id="modifying-the-app-to-make-using-sitemaps-easier"><a class="header" href="#modifying-the-app-to-make-using-sitemaps-easier">Modifying the app to make using sitemaps easier</a></h2>
  1941. <p>Preparing our app for sitemap generation is quite easy. We just need to extract
  1942. our segment definition into its own function.</p>
  1943. <pre><pre class="playground"><code class="language-rust no_run edition2021">
  1944. <span class="boring">#![allow(unused)]
  1945. </span><span class="boring">fn main() {
  1946. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  1947. </span><span class="boring">extern crate dioxus;
  1948. </span><span class="boring">use dioxus::prelude::*;
  1949. </span><span class="boring">extern crate dioxus_router;
  1950. </span><span class="boring">use dioxus_router::prelude::*;
  1951. </span><span class="boring">extern crate dioxus_ssr;
  1952. </span><span class="boring">fn Home(cx: Scope) -&gt; Element { unimplemented!() }
  1953. </span><span class="boring">fn Fixed(cx: Scope) -&gt; Element { unimplemented!() }
  1954. </span><span class="boring">fn Nested(cx: Scope) -&gt; Element { unimplemented!() }
  1955. </span><span class="boring">struct ParameterName;
  1956. </span><span class="boring">fn Parameter(cx: Scope) -&gt; Element { unimplemented!() }
  1957. </span><span class="boring">
  1958. </span>fn App(cx: Scope) -&gt; Element {
  1959. use_router(
  1960. cx,
  1961. &amp;|| RouterConfiguration {
  1962. ..Default::default()
  1963. },
  1964. &amp;prepare_routes
  1965. );
  1966. render! {
  1967. Outlet { }
  1968. }
  1969. }
  1970. fn prepare_routes() -&gt; Segment&lt;Component&gt; {
  1971. Segment::content(comp(Home))
  1972. .fixed(
  1973. &quot;fixed&quot;,
  1974. Route::content(comp(Fixed)).nested(
  1975. Segment::empty().fixed(&quot;nested&quot;, comp(Nested))
  1976. )
  1977. )
  1978. .catch_all((comp(Parameter), ParameterName { }))
  1979. }
  1980. <span class="boring">}
  1981. </span></code></pre></pre>
  1982. <h2 id="sitemaps-with-parameter-names"><a class="header" href="#sitemaps-with-parameter-names">Sitemaps with parameter names</a></h2>
  1983. <p>The first variant to generate sitemaps is very simple. It finds all routes
  1984. within the <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/routes/struct.Segment.html"><code>Segment</code></a> and adds them to the returned <code>Vec</code>.</p>
  1985. <p>Matching and parameter routes are represented by their <code>key</code>, prefixed with <code>\</code>.
  1986. Besides that <code>\</code>, all paths are URL encoded.</p>
  1987. <pre><pre class="playground"><code class="language-rust edition2021">
  1988. <span class="boring">#![allow(unused)]
  1989. </span><span class="boring">fn main() {
  1990. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  1991. </span><span class="boring">extern crate dioxus;
  1992. </span><span class="boring">use dioxus::prelude::*;
  1993. </span><span class="boring">extern crate dioxus_router;
  1994. </span><span class="boring">use dioxus_router::prelude::*;
  1995. </span><span class="boring">extern crate dioxus_ssr;
  1996. </span><span class="boring">fn Home(cx: Scope) -&gt; Element { unimplemented!() }
  1997. </span><span class="boring">fn Fixed(cx: Scope) -&gt; Element { unimplemented!() }
  1998. </span><span class="boring">fn Nested(cx: Scope) -&gt; Element { unimplemented!() }
  1999. </span><span class="boring">struct ParameterName;
  2000. </span><span class="boring">fn Parameter(cx: Scope) -&gt; Element { unimplemented!() }
  2001. </span><span class="boring">fn prepare_routes() -&gt; Segment&lt;Component&gt; {
  2002. </span><span class="boring"> Segment::content(comp(Home))
  2003. </span><span class="boring"> .fixed(
  2004. </span><span class="boring"> &quot;fixed&quot;,
  2005. </span><span class="boring"> Route::content(comp(Fixed)).nested(
  2006. </span><span class="boring"> Segment::empty().fixed(&quot;nested&quot;, comp(Nested))
  2007. </span><span class="boring"> )
  2008. </span><span class="boring"> )
  2009. </span><span class="boring"> .catch_all((comp(Parameter), ParameterName { }))
  2010. </span><span class="boring">}
  2011. </span>
  2012. let expected = vec![
  2013. &quot;/&quot;,
  2014. &quot;/fixed&quot;,
  2015. &quot;/fixed/nested&quot;,
  2016. // Usually, here would be a fourth result representing the parameter route.
  2017. // However, due to mdbook the name for this file would constantly change,
  2018. // which is why we cannot show it. It would look something like this:
  2019. // &quot;/\\your_crate::ParameterName&quot;,
  2020. ];
  2021. let mut sitemap = prepare_routes().gen_sitemap();
  2022. sitemap.remove(3); // see above
  2023. assert_eq!(sitemap, expected);
  2024. <span class="boring">}
  2025. </span></code></pre></pre>
  2026. <h2 id="sitemaps-with-actual-parameter-values"><a class="header" href="#sitemaps-with-actual-parameter-values">Sitemaps with actual parameter values</a></h2>
  2027. <p>The second variant to generate sitemaps is a bit more involved. When it
  2028. encounters a parameter route, it inserts all values with a matching <code>key</code> that
  2029. were provided to it.</p>
  2030. <p>Matching routes only add their path if the value matches their regex.</p>
  2031. <p>All paths are URL encoded.</p>
  2032. <pre><pre class="playground"><code class="language-rust edition2021">
  2033. <span class="boring">#![allow(unused)]
  2034. </span><span class="boring">fn main() {
  2035. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  2036. </span>use std::collections::{BTreeMap, HashSet};
  2037. <span class="boring">extern crate dioxus;
  2038. </span><span class="boring">use dioxus::prelude::*;
  2039. </span><span class="boring">extern crate dioxus_router;
  2040. </span><span class="boring">use dioxus_router::prelude::*;
  2041. </span><span class="boring">extern crate dioxus_ssr;
  2042. </span><span class="boring">fn Home(cx: Scope) -&gt; Element { unimplemented!() }
  2043. </span><span class="boring">fn Fixed(cx: Scope) -&gt; Element { unimplemented!() }
  2044. </span><span class="boring">fn Nested(cx: Scope) -&gt; Element { unimplemented!() }
  2045. </span><span class="boring">struct ParameterName;
  2046. </span><span class="boring">fn Parameter(cx: Scope) -&gt; Element { unimplemented!() }
  2047. </span><span class="boring">fn prepare_routes() -&gt; Segment&lt;Component&gt; {
  2048. </span><span class="boring"> Segment::content(comp(Home))
  2049. </span><span class="boring"> .fixed(
  2050. </span><span class="boring"> &quot;fixed&quot;,
  2051. </span><span class="boring"> Route::content(comp(Fixed)).nested(
  2052. </span><span class="boring"> Segment::empty().fixed(&quot;nested&quot;, comp(Nested))
  2053. </span><span class="boring"> )
  2054. </span><span class="boring"> )
  2055. </span><span class="boring"> .catch_all((comp(Parameter), ParameterName { }))
  2056. </span><span class="boring">}
  2057. </span>
  2058. let parameters = {
  2059. let mut parameters = BTreeMap::new();
  2060. parameters.insert(
  2061. Name::of::&lt;ParameterName&gt;(),
  2062. vec![
  2063. String::from(&quot;some-parameter-value&quot;),
  2064. String::from(&quot;other-parameter-value&quot;)
  2065. ]
  2066. );
  2067. parameters
  2068. };
  2069. let expected: Vec&lt;String&gt; = vec![
  2070. &quot;/&quot;,
  2071. &quot;/fixed&quot;,
  2072. &quot;/fixed/nested&quot;,
  2073. &quot;/some-parameter-value&quot;,
  2074. &quot;/other-parameter-value&quot;,
  2075. ].into_iter().map(String::from).collect();
  2076. assert_eq!(expected, prepare_routes().gen_parameter_sitemap(&amp;parameters));
  2077. <span class="boring">}
  2078. </span></code></pre></pre>
  2079. <div style="break-before: page; page-break-before: always;"></div><h1 id="routing-update-callback"><a class="header" href="#routing-update-callback">Routing Update Callback</a></h1>
  2080. <p>In some cases we might want to run custom code when the current route changes.
  2081. For this reason, the <a href="https://docs.rs/dioxus-router/latest/dioxus_router/hooks/struct.RouterConfiguration.html"><code>RouterConfiguration</code></a> exposes an <code>on_update</code> field.</p>
  2082. <h2 id="how-does-the-callback-behave"><a class="header" href="#how-does-the-callback-behave">How does the callback behave?</a></h2>
  2083. <p>The <code>on_update</code> is called whenever the current routing information changes. It
  2084. is called after the router updated its internal state, but before depended
  2085. components and hooks are updated.</p>
  2086. <p>If the callback returns a <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/navigation/enum.NavigationTarget.html"><code>NavigationTarget</code></a>, the router will replace the
  2087. current location with the specified target. It will not call the
  2088. <code>on_update</code> again.</p>
  2089. <p>If at any point the router encounters a
  2090. <a href="features/./failures/index.html">navigation failure</a>, it will go to the appropriate state
  2091. without calling the <code>on_update</code>. It doesn't matter if the invalid target
  2092. initiated the navigation, was found as a redirect target or returned by the
  2093. <code>on_update</code> itself.</p>
  2094. <h2 id="code-example-3"><a class="header" href="#code-example-3">Code Example</a></h2>
  2095. <pre><pre class="playground"><code class="language-rust edition2021">
  2096. <span class="boring">#![allow(unused)]
  2097. </span><span class="boring">fn main() {
  2098. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  2099. </span><span class="boring">extern crate dioxus;
  2100. </span><span class="boring">extern crate dioxus_router;
  2101. </span><span class="boring">extern crate dioxus_ssr;
  2102. </span><span class="boring">
  2103. </span>use std::sync::Arc;
  2104. use dioxus::prelude::*;
  2105. use dioxus_router::prelude::*;
  2106. fn App(cx: Scope) -&gt; Element {
  2107. use_router(
  2108. cx,
  2109. &amp;|| RouterConfiguration {
  2110. <span class="boring"> synchronous: true,
  2111. </span> on_update: Some(Arc::new(|state| -&gt; Option&lt;NavigationTarget&gt; {
  2112. if state.path == &quot;/&quot; {
  2113. return Some(&quot;/home&quot;.into());
  2114. }
  2115. None
  2116. })),
  2117. ..Default::default()
  2118. },
  2119. &amp;|| Segment::empty().fixed(&quot;home&quot;, comp(Content))
  2120. );
  2121. render! {
  2122. Outlet { }
  2123. }
  2124. }
  2125. fn Content(cx: Scope) -&gt; Element {
  2126. render! {
  2127. p { &quot;Some content&quot; }
  2128. }
  2129. }
  2130. <span class="boring">
  2131. </span><span class="boring">let mut vdom = VirtualDom::new(App);
  2132. </span><span class="boring">vdom.rebuild();
  2133. </span><span class="boring">assert_eq!(dioxus_ssr::render(&amp;mut vdom), &quot;&lt;p&gt;Some content&lt;/p&gt;&quot;);
  2134. </span><span class="boring">}
  2135. </span></code></pre></pre>
  2136. <div style="break-before: page; page-break-before: always;"></div><h1 id="overview"><a class="header" href="#overview">Overview</a></h1>
  2137. <p>In this guide you'll learn to effectively use Dioxus Router whether you're
  2138. building a small todo app or the next FAANG company. We will create a small
  2139. website with a blog, homepage, and more!</p>
  2140. <blockquote>
  2141. <p>To follow along with the router example, you'll need a working Dioxus app.
  2142. Check out the <a href="https://dioxuslabs.com/guide/">Dioxus book</a> to get started.</p>
  2143. </blockquote>
  2144. <blockquote>
  2145. <p>Make sure to add Dioxus Router as a dependency, as explained in the
  2146. <a href="example/../index.html">introduction</a>.</p>
  2147. </blockquote>
  2148. <h2 id="youll-learn-how-to"><a class="header" href="#youll-learn-how-to">You'll learn how to</a></h2>
  2149. <ul>
  2150. <li>Create routes and render &quot;pages&quot;.</li>
  2151. <li>Utilize nested routes, create a navigation bar, and render content for a
  2152. set of routes.</li>
  2153. <li>Gather URL parameters to dynamically display content.</li>
  2154. <li>Redirect your visitors wherever you want.</li>
  2155. </ul>
  2156. <blockquote>
  2157. <p><strong>Disclaimer</strong></p>
  2158. <p>The example will only display the features of Dioxus Router. It will not
  2159. include any actual functionality. To keep things simple we will only be using
  2160. a single file, this is not the recommended way of doing things with a real
  2161. application.</p>
  2162. </blockquote>
  2163. <p>You can find the complete application in the <a href="example/./full-code.html">full code</a>
  2164. chapter.</p>
  2165. <div style="break-before: page; page-break-before: always;"></div><h1 id="creating-our-first-route"><a class="header" href="#creating-our-first-route">Creating Our First Route</a></h1>
  2166. <p>In this chapter, we will start utilizing Dioxus Router and add a homepage and a
  2167. 404 page to our project.</p>
  2168. <h2 id="fundamentals"><a class="header" href="#fundamentals">Fundamentals</a></h2>
  2169. <p>Dioxus Router works based on a <a href="https://docs.rs/dioxus-router/latest/dioxus_router/hooks/fn.use_router.html"><code>use_router</code></a> hook, a route definition in pure
  2170. rust and <a href="https://docs.rs/dioxus-router/latest/dioxus_router/components/fn.Outlet.html"><code>Outlet</code></a> components. If you've ever used <a href="https://router.vuejs.org/">Vue Router</a>, you should
  2171. feel right at home with Dioxus Router.</p>
  2172. <p>First we need an actual page to route to! Let's add a homepage component:</p>
  2173. <pre><pre class="playground"><code class="language-rust no_run edition2021">
  2174. <span class="boring">#![allow(unused)]
  2175. </span><span class="boring">fn main() {
  2176. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  2177. </span><span class="boring">extern crate dioxus;
  2178. </span><span class="boring">use dioxus::prelude::*;
  2179. </span><span class="boring">
  2180. </span>fn Home(cx: Scope) -&gt; Element {
  2181. render! {
  2182. h1 { &quot;Welcome to the Dioxus Blog!&quot; }
  2183. }
  2184. }
  2185. <span class="boring">}
  2186. </span></code></pre></pre>
  2187. <h2 id="to-route-or-not-to-route"><a class="header" href="#to-route-or-not-to-route">To Route or Not to Route</a></h2>
  2188. <p>We want to use Dioxus Router to separate our application into different &quot;pages&quot;.
  2189. Dioxus Router will then determine which page to render based on the URL path.</p>
  2190. <p>To start using Dioxus Router, we need to use the <a href="https://docs.rs/dioxus-router/latest/dioxus_router/hooks/fn.use_router.html"><code>use_router</code></a> hook. All other
  2191. hooks and components the router provides can only be used as a descendant of a
  2192. component calling <a href="https://docs.rs/dioxus-router/latest/dioxus_router/hooks/fn.use_router.html"><code>use_router</code></a>.</p>
  2193. <p>The <a href="https://docs.rs/dioxus-router/latest/dioxus_router/hooks/fn.use_router.html"><code>use_router</code></a> hook takes three arguments:</p>
  2194. <ol>
  2195. <li><code>cx</code>, which is a common argument for all hooks.</li>
  2196. <li>A <a href="https://docs.rs/dioxus-router/latest/dioxus_router/hooks/struct.RouterConfiguration.html"><code>RouterConfiguration</code></a>, which allows us to modify its behavior.</li>
  2197. <li>A definition of all routes the application contains, in the form of its root
  2198. <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/routes/struct.Segment.html"><code>Segment</code></a>.</li>
  2199. </ol>
  2200. <pre><pre class="playground"><code class="language-rust no_run edition2021">
  2201. <span class="boring">#![allow(unused)]
  2202. </span><span class="boring">fn main() {
  2203. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  2204. </span><span class="boring">extern crate dioxus;
  2205. </span>use dioxus::prelude::*;
  2206. <span class="boring">extern crate dioxus_router;
  2207. </span>use dioxus_router::prelude::*;
  2208. <span class="boring">fn Home(cx: Scope) -&gt; Element { unimplemented!() }
  2209. </span>
  2210. fn App(cx: Scope) -&gt; Element {
  2211. use_router(
  2212. cx,
  2213. &amp;|| RouterConfiguration::default(),
  2214. &amp;|| Segment::content(comp(Home))
  2215. );
  2216. render! {
  2217. Outlet { }
  2218. }
  2219. }
  2220. <span class="boring">}
  2221. </span></code></pre></pre>
  2222. <p>If you head to your application's browser tab, you should now see the text
  2223. <code>Welcome to Dioxus Blog!</code> when on the root URL (<code>http://localhost:8080/</code>). If
  2224. you enter a different path for the URL, nothing should be displayed.</p>
  2225. <p>This is because we told Dioxus Router to render the <code>Home</code> component only when
  2226. the URL path is <code>/</code>. The <em>index</em> (<code>Segment::content()</code>) functionality we used
  2227. basically emulates how web servers treat <code>index.html</code> files.</p>
  2228. <h2 id="what-if-a-route-doesnt-exist"><a class="header" href="#what-if-a-route-doesnt-exist">What if a Route Doesn't Exist?</a></h2>
  2229. <p>In our example Dioxus Router doesn't render anything. Many sites also have a
  2230. &quot;404&quot; page for when a URL path leads to nowhere. Dioxus Router can do this too!</p>
  2231. <p>First, we create a new <code>PageNotFound</code> component.</p>
  2232. <pre><pre class="playground"><code class="language-rust no_run edition2021">
  2233. <span class="boring">#![allow(unused)]
  2234. </span><span class="boring">fn main() {
  2235. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  2236. </span><span class="boring">extern crate dioxus;
  2237. </span><span class="boring">use dioxus::prelude::*;
  2238. </span><span class="boring">
  2239. </span>fn PageNotFound(cx: Scope) -&gt; Element {
  2240. render! {
  2241. h1 { &quot;Page not found&quot; }
  2242. p { &quot;We are terribly sorry, but the page you requested doesn't exist.&quot; }
  2243. }
  2244. }
  2245. <span class="boring">}
  2246. </span></code></pre></pre>
  2247. <p>Now to tell Dioxus Router to render our new component when no route exists.</p>
  2248. <pre><pre class="playground"><code class="language-rust no_run edition2021">
  2249. <span class="boring">#![allow(unused)]
  2250. </span><span class="boring">fn main() {
  2251. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  2252. </span><span class="boring">extern crate dioxus;
  2253. </span><span class="boring">use dioxus::prelude::*;
  2254. </span><span class="boring">extern crate dioxus_router;
  2255. </span><span class="boring">use dioxus_router::prelude::*;
  2256. </span><span class="boring">fn Home(cx: Scope) -&gt; Element { unimplemented!() }
  2257. </span><span class="boring">fn PageNotFound(cx: Scope) -&gt; Element { unimplemented!() }
  2258. </span><span class="boring">
  2259. </span>fn App(cx: Scope) -&gt; Element {
  2260. use_router(
  2261. cx,
  2262. &amp;|| RouterConfiguration::default(),
  2263. &amp;|| {
  2264. Segment::content(comp(Home))
  2265. .fallback(comp(PageNotFound)) // this is new
  2266. }
  2267. );
  2268. render! {
  2269. Outlet { }
  2270. }
  2271. }
  2272. <span class="boring">}
  2273. </span></code></pre></pre>
  2274. <p>Now when you go to a route that doesn't exist, you should see the page not found
  2275. text.</p>
  2276. <h2 id="conclusion"><a class="header" href="#conclusion">Conclusion</a></h2>
  2277. <p>In this chapter we learned how to create a route and tell Dioxus Router what
  2278. component to render when the URL path is <code>/</code>. We also created a 404 page to
  2279. handle when a route doesn't exist. Next, we'll create the blog portion of our
  2280. site. We will utilize nested routes and URL parameters.</p>
  2281. <div style="break-before: page; page-break-before: always;"></div><h1 id="building-a-nest"><a class="header" href="#building-a-nest">Building a Nest</a></h1>
  2282. <p>Not a bird's nest! A nest of routes!</p>
  2283. <p>In this chapter we will begin to build the blog portion of our site which will
  2284. include links, nested URLs, and URL parameters. We will also explore the use
  2285. case of rendering components directly in the component calling <a href="https://docs.rs/dioxus-router/latest/dioxus_router/hooks/fn.use_router.html"><code>use_router</code></a>.</p>
  2286. <h2 id="site-navigation"><a class="header" href="#site-navigation">Site Navigation</a></h2>
  2287. <p>Our site visitors won't know all the available pages and blogs on our site so we
  2288. should provide a navigation bar for them.
  2289. Let's create a new <code>NavBar</code> component:</p>
  2290. <pre><pre class="playground"><code class="language-rust no_run edition2021">
  2291. <span class="boring">#![allow(unused)]
  2292. </span><span class="boring">fn main() {
  2293. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  2294. </span><span class="boring">extern crate dioxus;
  2295. </span><span class="boring">use dioxus::prelude::*;
  2296. </span><span class="boring">extern crate dioxus_router;
  2297. </span><span class="boring">use dioxus_router::prelude::*;
  2298. </span><span class="boring">
  2299. </span>fn NavBar(cx: Scope) -&gt; Element {
  2300. render! {
  2301. nav {
  2302. ul { }
  2303. }
  2304. }
  2305. }
  2306. <span class="boring">}
  2307. </span></code></pre></pre>
  2308. <p>Our navbar will be a list of links going between our pages. We could always use
  2309. an HTML anchor element but that would cause our page to reload unnecessarily.
  2310. Instead we want to use the <a href="https://docs.rs/dioxus-router/latest/dioxus_router/components/fn.Link.html"><code>Link</code></a> component provided by Dioxus Router.</p>
  2311. <p>The <a href="https://docs.rs/dioxus-router/latest/dioxus_router/components/fn.Link.html"><code>Link</code></a> is similar to a regular <code>a</code> tag. It takes a target (for now a path,
  2312. more on other targets later) and an element. Let's add our links</p>
  2313. <pre><pre class="playground"><code class="language-rust no_run edition2021">
  2314. <span class="boring">#![allow(unused)]
  2315. </span><span class="boring">fn main() {
  2316. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  2317. </span><span class="boring">extern crate dioxus;
  2318. </span><span class="boring">use dioxus::prelude::*;
  2319. </span><span class="boring">extern crate dioxus_router;
  2320. </span><span class="boring">use dioxus_router::prelude::*;
  2321. </span><span class="boring">
  2322. </span>fn NavBar(cx: Scope) -&gt; Element {
  2323. render! {
  2324. nav {
  2325. ul {
  2326. // new stuff starts here
  2327. li { Link {
  2328. target: NavigationTarget::Internal(String::from(&quot;/&quot;)),
  2329. &quot;Home&quot;
  2330. } }
  2331. li { Link {
  2332. target: &quot;/blog&quot;, // short form
  2333. &quot;Blog&quot;
  2334. } }
  2335. // new stuff ends here
  2336. }
  2337. }
  2338. }
  2339. }
  2340. <span class="boring">}
  2341. </span></code></pre></pre>
  2342. <blockquote>
  2343. <p>Using this method, the <a href="https://docs.rs/dioxus-router/latest/dioxus_router/components/fn.Link.html"><code>Link</code></a> component only works for links within our
  2344. application. To learn more about navigation targets see
  2345. <a href="example/./navigation-targets.html">here</a>.</p>
  2346. </blockquote>
  2347. <p>And finally, we add the navbar component in our app component:</p>
  2348. <pre><pre class="playground"><code class="language-rust no_run edition2021">
  2349. <span class="boring">#![allow(unused)]
  2350. </span><span class="boring">fn main() {
  2351. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  2352. </span><span class="boring">extern crate dioxus;
  2353. </span><span class="boring">use dioxus::prelude::*;
  2354. </span><span class="boring">extern crate dioxus_router;
  2355. </span><span class="boring">use dioxus_router::prelude::*;
  2356. </span><span class="boring">fn Home(cx: Scope) -&gt; Element { unimplemented!() }
  2357. </span><span class="boring">fn NavBar(cx: Scope) -&gt; Element { unimplemented!() }
  2358. </span><span class="boring">fn PageNotFound(cx: Scope) -&gt; Element { unimplemented!() }
  2359. </span><span class="boring">
  2360. </span>fn App(cx: Scope) -&gt; Element {
  2361. use_router(
  2362. cx,
  2363. &amp;|| RouterConfiguration::default(),
  2364. &amp;|| Segment::content(comp(Home)).fallback(comp(PageNotFound))
  2365. );
  2366. render! {
  2367. NavBar { } // this is new
  2368. Outlet { }
  2369. }
  2370. }
  2371. <span class="boring">}
  2372. </span></code></pre></pre>
  2373. <p>Now you should see a list of links near the top of your page. Click on one and
  2374. you should seamlessly travel between pages.</p>
  2375. <h3 id="active-link-styling"><a class="header" href="#active-link-styling">Active Link Styling</a></h3>
  2376. <p>You might want to style links differently, when their page is currently open.
  2377. To achieve this, we can tell the <a href="https://docs.rs/dioxus-router/latest/dioxus_router/components/fn.Link.html"><code>Link</code></a> to give its internal <code>a</code> tag a class
  2378. in that case.</p>
  2379. <pre><pre class="playground"><code class="language-rust no_run edition2021">
  2380. <span class="boring">#![allow(unused)]
  2381. </span><span class="boring">fn main() {
  2382. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  2383. </span><span class="boring">extern crate dioxus;
  2384. </span><span class="boring">use dioxus::prelude::*;
  2385. </span><span class="boring">extern crate dioxus_router;
  2386. </span><span class="boring">use dioxus_router::prelude::*;
  2387. </span><span class="boring">
  2388. </span>fn NavBar(cx: Scope) -&gt; Element {
  2389. render! {
  2390. nav {
  2391. ul {
  2392. li { Link {
  2393. target: NavigationTarget::Internal(String::from(&quot;/&quot;)),
  2394. active_class: &quot;active&quot;, // this is new
  2395. &quot;Home&quot;
  2396. } }
  2397. li { Link {
  2398. target: &quot;/blog&quot;,
  2399. active_class: &quot;active&quot;, // this is new
  2400. &quot;Blog&quot;
  2401. } }
  2402. }
  2403. }
  2404. }
  2405. }
  2406. <span class="boring">}
  2407. </span></code></pre></pre>
  2408. <blockquote>
  2409. <p>This will not be reflected in the <a href="example/./full-code.html">full example code</a>.</p>
  2410. </blockquote>
  2411. <h2 id="url-parameters-and-nested-routes"><a class="header" href="#url-parameters-and-nested-routes">URL Parameters and Nested Routes</a></h2>
  2412. <p>Many websites such as GitHub put parameters in their URL. For example,
  2413. <code>https://github.com/DioxusLabs</code> utilizes the text after the domain to
  2414. dynamically search and display content about an organization.</p>
  2415. <p>We want to store our blogs in a database and load them as needed. This'll help
  2416. prevent our app from being bloated therefor providing faster load times. We also
  2417. want our users to be able to send people a link to a specific blog post.</p>
  2418. <p>We could utilize a search page that loads a blog when clicked but then our users
  2419. won't be able to share our blogs easily. This is where URL parameters come in.</p>
  2420. <p>The path to our blog will look like <code>/blog/myBlogPage</code>, <code>myBlogPage</code> being the
  2421. URL parameter.</p>
  2422. <p>First, lets create a component that wraps around all blog content. This allows
  2423. us to add a heading that tells the user they are on the blog.</p>
  2424. <pre><pre class="playground"><code class="language-rust no_run edition2021">
  2425. <span class="boring">#![allow(unused)]
  2426. </span><span class="boring">fn main() {
  2427. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  2428. </span><span class="boring">extern crate dioxus;
  2429. </span><span class="boring">use dioxus::prelude::*;
  2430. </span><span class="boring">extern crate dioxus_router;
  2431. </span><span class="boring">use dioxus_router::prelude::*;
  2432. </span><span class="boring">
  2433. </span>fn Blog(cx: Scope) -&gt; Element {
  2434. render! {
  2435. h1 { &quot;Blog&quot; }
  2436. Outlet {}
  2437. }
  2438. }
  2439. <span class="boring">}
  2440. </span></code></pre></pre>
  2441. <blockquote>
  2442. <p>Note the <code>Outlet { }</code> component. For the components of a nested route to be
  2443. rendered, we need an equally nested outlet. For more details, see the
  2444. <a href="example/../features/routes/nested.html">nested routes</a> chapter of the features section.</p>
  2445. </blockquote>
  2446. <p>Now we'll create another index component, that'll be displayed when no blog post
  2447. is selected:</p>
  2448. <pre><pre class="playground"><code class="language-rust no_run edition2021">
  2449. <span class="boring">#![allow(unused)]
  2450. </span><span class="boring">fn main() {
  2451. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  2452. </span><span class="boring">extern crate dioxus;
  2453. </span><span class="boring">use dioxus::prelude::*;
  2454. </span><span class="boring">extern crate dioxus_router;
  2455. </span><span class="boring">use dioxus_router::prelude::*;
  2456. </span><span class="boring">
  2457. </span>fn BlogList(cx: Scope) -&gt; Element {
  2458. render! {
  2459. h2 { &quot;Choose a post&quot; }
  2460. ul {
  2461. li { Link {
  2462. target: &quot;/blog/1&quot;,
  2463. &quot;Read the first blog post&quot;
  2464. } }
  2465. li { Link {
  2466. target: &quot;/blog/2&quot;,
  2467. &quot;Read the second blog post&quot;
  2468. } }
  2469. }
  2470. }
  2471. }
  2472. <span class="boring">}
  2473. </span></code></pre></pre>
  2474. <p>We also need to create a component that displays an actual blog post. Within
  2475. this component we can use the <code>use_route</code> hook to gain access to our URL
  2476. parameters:</p>
  2477. <pre><pre class="playground"><code class="language-rust no_run edition2021">
  2478. <span class="boring">#![allow(unused)]
  2479. </span><span class="boring">fn main() {
  2480. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  2481. </span><span class="boring">extern crate dioxus;
  2482. </span><span class="boring">use dioxus::prelude::*;
  2483. </span><span class="boring">extern crate dioxus_router;
  2484. </span><span class="boring">use dioxus_router::prelude::*;
  2485. </span><span class="boring">
  2486. </span>struct PostId;
  2487. fn BlogPost(cx: Scope) -&gt; Element {
  2488. let route = use_route(cx).unwrap();
  2489. let post_id = route.parameter::&lt;PostId&gt;();
  2490. let post = post_id
  2491. .map(|id| id.to_string())
  2492. .unwrap_or(String::from(&quot;unknown&quot;));
  2493. render! {
  2494. h2 { &quot;Blog Post: {post}&quot;}
  2495. }
  2496. }
  2497. <span class="boring">}
  2498. </span></code></pre></pre>
  2499. <p>Finally, let's tell our router about those components.</p>
  2500. <pre><pre class="playground"><code class="language-rust no_run edition2021">
  2501. <span class="boring">#![allow(unused)]
  2502. </span><span class="boring">fn main() {
  2503. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  2504. </span><span class="boring">extern crate dioxus;
  2505. </span><span class="boring">use dioxus::prelude::*;
  2506. </span><span class="boring">extern crate dioxus_router;
  2507. </span><span class="boring">use dioxus_router::prelude::*;
  2508. </span><span class="boring">fn Blog(cx: Scope) -&gt; Element { unimplemented!() }
  2509. </span><span class="boring">fn BlogList(cx: Scope) -&gt; Element { unimplemented!() }
  2510. </span><span class="boring">struct PostId;
  2511. </span><span class="boring">fn BlogPost(cx: Scope) -&gt; Element { unimplemented!() }
  2512. </span><span class="boring">fn Home(cx: Scope) -&gt; Element { unimplemented!() }
  2513. </span><span class="boring">fn NavBar(cx: Scope) -&gt; Element { unimplemented!() }
  2514. </span><span class="boring">fn PageNotFound(cx: Scope) -&gt; Element { unimplemented!() }
  2515. </span><span class="boring">
  2516. </span>fn App(cx: Scope) -&gt; Element {
  2517. use_router(
  2518. cx,
  2519. &amp;|| RouterConfiguration::default(),
  2520. &amp;|| {
  2521. Segment::content(comp(Home))
  2522. // new stuff starts here
  2523. .fixed(&quot;blog&quot;, Route::content(comp(Blog)).nested(
  2524. Segment::content(comp(BlogList))
  2525. .catch_all((comp(BlogPost), PostId { }))
  2526. ))
  2527. // new stuff ends here
  2528. .fallback(comp(PageNotFound))
  2529. }
  2530. );
  2531. render! {
  2532. NavBar { }
  2533. Outlet { }
  2534. }
  2535. }
  2536. <span class="boring">}
  2537. </span></code></pre></pre>
  2538. <p>That's it! If you head to <code>/blog/1</code> you should see our sample post.</p>
  2539. <h2 id="conclusion-1"><a class="header" href="#conclusion-1">Conclusion</a></h2>
  2540. <p>In this chapter we utilized Dioxus Router's Link, URL Parameter, and <code>use_route</code>
  2541. functionality to build the blog portion of our application. In the next chapter,
  2542. we will go over how navigation targets (like the one we passed to our links)
  2543. work.</p>
  2544. <div style="break-before: page; page-break-before: always;"></div><h1 id="navigation-targets"><a class="header" href="#navigation-targets">Navigation Targets</a></h1>
  2545. <p>In the previous chapter we learned how to create links to pages within our app.
  2546. We told them where to go using the <code>target</code> property. This property takes a
  2547. <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/navigation/enum.NavigationTarget.html"><code>NavigationTarget</code></a>.</p>
  2548. <h2 id="what-is-a-navigation-target"><a class="header" href="#what-is-a-navigation-target">What is a navigation target?</a></h2>
  2549. <p>A <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/navigation/enum.NavigationTarget.html"><code>NavigationTarget</code></a> is similar to the <code>href</code> of an HTML anchor element.It
  2550. tells the router where to navigate to. The Dioxus Router knows three kinds of
  2551. navigation targets:</p>
  2552. <ul>
  2553. <li><a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/navigation/enum.NavigationTarget.html#variant.Internal"><code>Internal</code></a>: we already saw that. It's basically an <code>href</code>, but cannot
  2554. link to content outside our app.</li>
  2555. <li><a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/navigation/enum.NavigationTarget.html#variant.External"><code>External</code></a>: This works exactly like an HTML anchors <code>href</code>. In fact,
  2556. it is just passed through. Don't use this for in-app navigation as it'll
  2557. trigger a page reload by the browser.</li>
  2558. <li><a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/navigation/enum.NavigationTarget.html#variant.Named"><code>Named</code></a>: this is the most interesting form of navigation target. We'll look
  2559. at it in detail in this chapter.</li>
  2560. </ul>
  2561. <h2 id="external-navigation-1"><a class="header" href="#external-navigation-1">External navigation</a></h2>
  2562. <p>If we need a link to an external page we can do it like this:</p>
  2563. <pre><pre class="playground"><code class="language-rust no_run edition2021">
  2564. <span class="boring">#![allow(unused)]
  2565. </span><span class="boring">fn main() {
  2566. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  2567. </span><span class="boring">extern crate dioxus;
  2568. </span><span class="boring">use dioxus::prelude::*;
  2569. </span><span class="boring">extern crate dioxus_router;
  2570. </span><span class="boring">use dioxus_router::prelude::*;
  2571. </span><span class="boring">
  2572. </span>fn GoToDioxus(cx: Scope) -&gt; Element {
  2573. render! {
  2574. Link {
  2575. target: NavigationTarget::External(&quot;https://dioxuslabs.com&quot;.into()),
  2576. &quot;Explicit ExternalTarget target&quot;
  2577. }
  2578. Link {
  2579. target: &quot;https://dioxuslabs.com&quot;, // short form
  2580. &quot;Implicit ExternalTarget target&quot;
  2581. }
  2582. }
  2583. }
  2584. <span class="boring">}
  2585. </span></code></pre></pre>
  2586. <blockquote>
  2587. <p>Note that we can use a <code>str</code>, just like with <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/navigation/enum.NavigationTarget.html#variant.Internal"><code>Internal</code></a>s. The router will
  2588. convert a <code>str</code> to an <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/navigation/enum.NavigationTarget.html#variant.External"><code>External</code></a> if the URL is absolute.</p>
  2589. </blockquote>
  2590. <h2 id="named-navigation-1"><a class="header" href="#named-navigation-1">Named navigation</a></h2>
  2591. <p>When defining our routes, we can optionally give them unique static names. This
  2592. is required for a feature we call named navigation.</p>
  2593. <p>Up to now, when creating links we told the router the exact path to go to. With
  2594. named navigation we instead give it a name, and let it figure out the path.</p>
  2595. <p>This has several advantages:</p>
  2596. <ul>
  2597. <li>We don't have to remember absolute paths or care about what the current path
  2598. is.</li>
  2599. <li>Changing paths later on won't break internal links.</li>
  2600. <li>Paths can easily be localized without affecting app logic.</li>
  2601. <li>The compiler makes sure we don't have typos.</li>
  2602. </ul>
  2603. <p>Let's try that now! First, we give our blog post route a name. We can reuse our
  2604. <code>BlogPost</code> component as a name.</p>
  2605. <pre><pre class="playground"><code class="language-rust no_run edition2021">
  2606. <span class="boring">#![allow(unused)]
  2607. </span><span class="boring">fn main() {
  2608. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  2609. </span><span class="boring">extern crate dioxus;
  2610. </span><span class="boring">use dioxus::prelude::*;
  2611. </span><span class="boring">extern crate dioxus_router;
  2612. </span><span class="boring">use dioxus_router::prelude::*;
  2613. </span><span class="boring">fn Blog(cx: Scope) -&gt; Element { unimplemented!() }
  2614. </span><span class="boring">fn BlogList(cx: Scope) -&gt; Element { unimplemented!() }
  2615. </span><span class="boring">struct PostId;
  2616. </span><span class="boring">fn BlogPost(cx: Scope) -&gt; Element { unimplemented!() }
  2617. </span><span class="boring">fn Home(cx: Scope) -&gt; Element { unimplemented!() }
  2618. </span><span class="boring">fn PageNotFound(cx: Scope) -&gt; Element { unimplemented!() }
  2619. </span><span class="boring">
  2620. </span>struct BlogPostName;
  2621. fn App(cx: Scope) -&gt; Element {
  2622. use_router(
  2623. cx,
  2624. &amp;|| RouterConfiguration::default(),
  2625. &amp;|| {
  2626. Segment::content(comp(Home))
  2627. .fixed(&quot;blog&quot;, Route::content(comp(Blog)).nested(
  2628. Segment::content(comp(BlogList)).catch_all(
  2629. ParameterRoute::content::&lt;PostId&gt;(comp(BlogPost))
  2630. .name::&lt;BlogPostName&gt;() // this is new
  2631. )
  2632. ))
  2633. .fallback(comp(PageNotFound))
  2634. }
  2635. );
  2636. // ...
  2637. <span class="boring"> unimplemented!()
  2638. </span>}
  2639. <span class="boring">}
  2640. </span></code></pre></pre>
  2641. <p>Now we can change the targets of the links in our <code>BlogList</code> component.</p>
  2642. <pre><pre class="playground"><code class="language-rust no_run edition2021">
  2643. <span class="boring">#![allow(unused)]
  2644. </span><span class="boring">fn main() {
  2645. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  2646. </span><span class="boring">extern crate dioxus;
  2647. </span><span class="boring">use dioxus::prelude::*;
  2648. </span><span class="boring">extern crate dioxus_router;
  2649. </span><span class="boring">use dioxus_router::prelude::*;
  2650. </span><span class="boring">struct PostId;
  2651. </span><span class="boring">struct BlogPostName;
  2652. </span><span class="boring">fn BlogPost(cx: Scope) -&gt; Element { unimplemented!() }
  2653. </span><span class="boring">
  2654. </span>fn BlogList(cx: Scope) -&gt; Element {
  2655. render! {
  2656. h2 { &quot;Choose a post&quot; }
  2657. ul {
  2658. li { Link {
  2659. target: named::&lt;BlogPostName&gt;().parameter::&lt;PostId&gt;(&quot;1&quot;),
  2660. &quot;Read the first blog post&quot;
  2661. } }
  2662. li { Link {
  2663. target: named::&lt;BlogPostName&gt;()
  2664. .parameter::&lt;PostId&gt;(&quot;1&quot;)
  2665. .query(&quot;query&quot;),
  2666. &quot;Read the second blog post&quot;
  2667. } }
  2668. }
  2669. }
  2670. }
  2671. <span class="boring">}
  2672. </span></code></pre></pre>
  2673. <p>As you can see, a <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/navigation/enum.NavigationTarget.html#variant.Named"><code>Named</code></a> requires three fields:</p>
  2674. <ol>
  2675. <li>the name to navigate to</li>
  2676. <li>a <code>Vec</code> containing all parameters that need to be inserted into the path</li>
  2677. <li>optionally a query string to use.</li>
  2678. </ol>
  2679. <h3 id="the-special-root-index-name"><a class="header" href="#the-special-root-index-name">The special root index name</a></h3>
  2680. <p>Whether we define any names or not, the router always knows about the
  2681. <a href="https://docs.rs/dioxus-router-core/latest/dioxus_router_core/prelude/struct.RootIndex.html"><code>RootIndex</code></a> name. Navigating to it tells the router to go to <code>/</code>.</p>
  2682. <p>We can change the link in our <code>NavBar</code> component to take advantage of that.</p>
  2683. <pre><pre class="playground"><code class="language-rust no_run edition2021">
  2684. <span class="boring">#![allow(unused)]
  2685. </span><span class="boring">fn main() {
  2686. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  2687. </span><span class="boring">extern crate dioxus;
  2688. </span><span class="boring">use dioxus::prelude::*;
  2689. </span><span class="boring">extern crate dioxus_router;
  2690. </span><span class="boring">use dioxus_router::prelude::*;
  2691. </span><span class="boring">
  2692. </span>fn NavBar(cx: Scope) -&gt; Element {
  2693. render! {
  2694. nav {
  2695. ul {
  2696. li { Link { target: named::&lt;RootIndex&gt;(), &quot;Home&quot; } }
  2697. li { Link { target: &quot;/blog&quot;, &quot;Blog&quot; } }
  2698. }
  2699. }
  2700. }
  2701. }
  2702. <span class="boring">}
  2703. </span></code></pre></pre>
  2704. <div style="break-before: page; page-break-before: always;"></div><h1 id="redirection-perfection"><a class="header" href="#redirection-perfection">Redirection Perfection</a></h1>
  2705. <p>You're well on your way to becoming a routing master!</p>
  2706. <p>In this chapter we will cover utilizing redirects so you can take Rickrolling to
  2707. the next level.</p>
  2708. <h2 id="what-is-this-redirect-thing"><a class="header" href="#what-is-this-redirect-thing">What Is This Redirect Thing?</a></h2>
  2709. <p>A redirect is very simple. When dioxus encounters a redirect while finding out
  2710. what components to render, it will redirect the user to the target of the
  2711. redirect.</p>
  2712. <p>As a simple example, let's say you want user to still land on your blog, even
  2713. if they used the path <code>/myblog</code>.</p>
  2714. <p>All we need to do is update our route definition in our app component:</p>
  2715. <pre><pre class="playground"><code class="language-rust no_run edition2021">
  2716. <span class="boring">#![allow(unused)]
  2717. </span><span class="boring">fn main() {
  2718. </span><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  2719. </span><span class="boring">extern crate dioxus;
  2720. </span><span class="boring">use dioxus::prelude::*;
  2721. </span><span class="boring">extern crate dioxus_router;
  2722. </span><span class="boring">use dioxus_router::prelude::*;
  2723. </span><span class="boring">fn Blog(cx: Scope) -&gt; Element { unimplemented!() }
  2724. </span><span class="boring">fn BlogList(cx: Scope) -&gt; Element { unimplemented!() }
  2725. </span><span class="boring">struct PostId;
  2726. </span><span class="boring">struct BlogPostName;
  2727. </span><span class="boring">fn BlogPost(cx: Scope) -&gt; Element { unimplemented!() }
  2728. </span><span class="boring">fn Home(cx: Scope) -&gt; Element { unimplemented!() }
  2729. </span><span class="boring">fn NavBar(cx: Scope) -&gt; Element { unimplemented!() }
  2730. </span><span class="boring">fn PageNotFound(cx: Scope) -&gt; Element { unimplemented!() }
  2731. </span><span class="boring">fn App(cx: Scope) -&gt; Element {
  2732. </span>use_router(
  2733. cx,
  2734. &amp;|| RouterConfiguration::default(),
  2735. &amp;|| {
  2736. Segment::content(comp(Home))
  2737. .fixed(&quot;blog&quot;, Route::content(comp(Blog)).nested(
  2738. Segment::content(comp(BlogList)).catch_all(
  2739. ParameterRoute::content::&lt;PostId&gt;(comp(BlogPost))
  2740. .name::&lt;BlogPostName&gt;()
  2741. )
  2742. ))
  2743. .fixed(&quot;myblog&quot;, &quot;/blog&quot;) // this is new
  2744. .fallback(comp(PageNotFound))
  2745. }
  2746. );
  2747. <span class="boring">unimplemented!()
  2748. </span><span class="boring">}
  2749. </span><span class="boring">}
  2750. </span></code></pre></pre>
  2751. <p>That's it! Now your users will be redirected to the blog.</p>
  2752. <p>Notice that the <code>&quot;/blog&quot;</code> <code>str</code> is a <a href="example/./navigation-targets.html">navigation target</a>.
  2753. We could also use external or named targets.</p>
  2754. <h3 id="conclusion-2"><a class="header" href="#conclusion-2">Conclusion</a></h3>
  2755. <p>Well done! You've completed the Dioxus Router guide book. You've built a small
  2756. application and learned about the many things you can do with Dioxus Router.
  2757. To continue your journey, you can find a list of challenges down below, or you
  2758. can check out the <a href="https://docs.rs/dioxus-router/">API reference</a>.</p>
  2759. <h3 id="challenges"><a class="header" href="#challenges">Challenges</a></h3>
  2760. <ul>
  2761. <li>Organize your components into seperate files for better maintainability.</li>
  2762. <li>Give your app some style if you haven't already.</li>
  2763. <li>Build an about page so your visitors know who you are.</li>
  2764. <li>Add a user system that uses URL parameters.</li>
  2765. <li>Create a simple admin system to create, delete, and edit blogs.</li>
  2766. <li>If you want to go to the max, hook up your application to a rest API and database.</li>
  2767. </ul>
  2768. <div style="break-before: page; page-break-before: always;"></div><h1 id="full-code-3"><a class="header" href="#full-code-3">Full Code</a></h1>
  2769. <pre><pre class="playground"><code class="language-rust no_run edition2021"><span class="boring">// Hidden lines (like this one) make the documentation tests work.
  2770. </span><span class="boring">extern crate dioxus;
  2771. </span><span class="boring">extern crate dioxus_router;
  2772. </span><span class="boring">extern crate dioxus_web;
  2773. </span>use dioxus::prelude::*;
  2774. use dioxus_router::prelude::*;
  2775. fn main() {
  2776. dioxus_web::launch(App);
  2777. }
  2778. fn App(cx: Scope) -&gt; Element {
  2779. use_router(
  2780. cx,
  2781. &amp;|| RouterConfiguration::default(),
  2782. &amp;|| {
  2783. Segment::content(comp(Home))
  2784. .fixed(&quot;blog&quot;, Route::content(comp(Blog)).nested(
  2785. Segment::content(comp(BlogList)).catch_all(
  2786. ParameterRoute::content::&lt;PostId&gt;(comp(BlogPost))
  2787. .name::&lt;BlogPostName&gt;()
  2788. )
  2789. ))
  2790. .fixed(&quot;myblog&quot;, &quot;/blog&quot;) // this is new
  2791. .fallback(comp(PageNotFound))
  2792. }
  2793. );
  2794. render! {
  2795. NavBar {}
  2796. Outlet {}
  2797. }
  2798. }
  2799. fn NavBar(cx: Scope) -&gt; Element {
  2800. render! {
  2801. nav {
  2802. ul {
  2803. li { Link { target: named::&lt;RootIndex&gt;(), &quot;Home&quot; } }
  2804. li { Link { target: &quot;/blog&quot;, &quot;Blog&quot; } }
  2805. }
  2806. }
  2807. }
  2808. }
  2809. fn Home(cx: Scope) -&gt; Element {
  2810. render! {
  2811. h1 { &quot;Welcome to the Dioxus Blog!&quot; }
  2812. }
  2813. }
  2814. fn Blog(cx: Scope) -&gt; Element {
  2815. render! {
  2816. h1 { &quot;Blog&quot; }
  2817. Outlet {}
  2818. }
  2819. }
  2820. fn BlogList(cx: Scope) -&gt; Element {
  2821. render! {
  2822. h2 { &quot;Choose a post&quot; }
  2823. ul {
  2824. li { Link {
  2825. target: named::&lt;BlogPostName&gt;().parameter::&lt;PostId&gt;(&quot;1&quot;),
  2826. &quot;Read the first blog post&quot;
  2827. } }
  2828. li { Link {
  2829. target: named::&lt;BlogPostName&gt;().parameter::&lt;PostId&gt;(&quot;2&quot;),
  2830. &quot;Read the second blog post&quot;
  2831. } }
  2832. }
  2833. }
  2834. }
  2835. struct PostId;
  2836. struct BlogPostName;
  2837. fn BlogPost(cx: Scope) -&gt; Element {
  2838. let route = use_route(cx).unwrap();
  2839. let post_id = route.parameter::&lt;PostId&gt;();
  2840. let post = post_id
  2841. .map(|id| id.to_string())
  2842. .unwrap_or(String::from(&quot;unknown&quot;));
  2843. render! {
  2844. h2 { &quot;Blog Post: {post}&quot;}
  2845. }
  2846. }
  2847. fn PageNotFound(cx: Scope) -&gt; Element {
  2848. render! {
  2849. h1 { &quot;Page not found&quot; }
  2850. p { &quot;We are terribly sorry, but the page you requested doesn't exist.&quot; }
  2851. }
  2852. }
  2853. </code></pre></pre>
  2854. </main>
  2855. <nav class="nav-wrapper" aria-label="Page navigation">
  2856. <!-- Mobile navigation buttons -->
  2857. <div style="clear: both"></div>
  2858. </nav>
  2859. </div>
  2860. </div>
  2861. <nav class="nav-wide-wrapper" aria-label="Page navigation">
  2862. </nav>
  2863. </div>
  2864. <script type="text/javascript">
  2865. window.playground_copyable = true;
  2866. </script>
  2867. <script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
  2868. <script src="mark.min.js" type="text/javascript" charset="utf-8"></script>
  2869. <script src="searcher.js" type="text/javascript" charset="utf-8"></script>
  2870. <script src="clipboard.min.js" type="text/javascript" charset="utf-8"></script>
  2871. <script src="highlight.js" type="text/javascript" charset="utf-8"></script>
  2872. <script src="book.js" type="text/javascript" charset="utf-8"></script>
  2873. <!-- Custom JS scripts -->
  2874. <script type="text/javascript">
  2875. window.addEventListener('load', function() {
  2876. window.setTimeout(window.print, 100);
  2877. });
  2878. </script>
  2879. </body>
  2880. </html>