فهرست منبع

Docs: update readme and usage doc for router

Jonathan Kelley 3 سال پیش
والد
کامیت
46a42c5ef9
2فایلهای تغییر یافته به همراه250 افزوده شده و 13 حذف شده
  1. 56 13
      packages/router/README.md
  2. 194 0
      packages/router/usage.md

+ 56 - 13
packages/router/README.md

@@ -1,6 +1,55 @@
-# Routing for Dioxus App
+<div align="center">
+  <h1>Dioxus Router</h1>
+</div>
 
-DioxusRouter adds React-Router style routing to your Dioxus apps. Works in browser, SSR, and natively.
+
+<div align="center">
+  <!-- Crates version -->
+  <a href="https://crates.io/crates/dioxus">
+    <img src="https://img.shields.io/crates/v/dioxus.svg?style=flat-square"
+    alt="Crates.io version" />
+  </a>
+  <!-- Downloads -->
+  <a href="https://crates.io/crates/dioxus">
+    <img src="https://img.shields.io/crates/d/dioxus.svg?style=flat-square"
+      alt="Download" />
+  </a>
+  <!-- docs -->
+  <a href="https://docs.rs/dioxus">
+    <img src="https://img.shields.io/badge/docs-latest-blue.svg?style=flat-square"
+      alt="docs.rs docs" />
+  </a>
+  <!-- CI -->
+  <a href="https://github.com/jkelleyrtp/dioxus/actions">
+    <img src="https://github.com/dioxuslabs/dioxus/actions/workflows/main.yml/badge.svg"
+      alt="CI status" />
+  </a>
+
+  <!--Awesome -->
+  <a href="https://github.com/dioxuslabs/awesome-dioxus">
+    <img src="https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg" alt="Awesome Page" />
+  </a>
+  <!-- Discord -->
+  <a href="https://discord.gg/XgGxMSkvUM">
+    <img src="https://img.shields.io/discord/899851952891002890.svg?logo=discord&style=flat-square" alt="Discord Link" />
+  </a>
+</div>
+
+
+
+<div align="center">
+  <h3>
+    <a href="https://dioxuslabs.com"> Website </a>
+    <span> | </span>
+    <a href="https://github.com/DioxusLabs/example-projects"> Examples </a>
+    <span> | </span>
+    <a href="https://dioxuslabs.com/guide"> Guide (0.1.8) </a>
+    <span> | </span>
+    <a href="https://dioxuslabs.com/nightly/guide"> Guide (Master) </a>
+  </h3>
+</div>
+
+Dioxus Router is a first-party Router for all your Dioxus Apps. It provides a React-Router style interface that works anywhere: across the browser, SSR, and natively.
 
 ```rust
 fn app() {
@@ -14,16 +63,10 @@ fn app() {
 }
 ```
 
-Then, in your route, you can choose to parse the Route any way you want through `use_route`.
-```rust
-let id: usize = use_route(&cx).segment("id")?;
-
-let state: CustomState = use_route(&cx).parse()?;
-```
 
-Adding links into your app:
-```rust
-Link { to: "id/{id}" }
-```
+## Resources
 
-Currently, the router is only supported in a web environment, but we plan to add 1st-party support via the context API when new renderers are available.
+- See the mdbook
+- See the one-page brief
+- See the guide on the doc site
+- The crates.io API

+ 194 - 0
packages/router/usage.md

@@ -0,0 +1,194 @@
+
+## Usage
+
+Using Dioxus Router is pretty simple. Add a top-level Router to your app (not necessary but good practice) and then start adding routes, specifying the "to" field:
+
+```rust
+fn app() {
+    cx.render(rsx! {
+        Router {
+            Route { to: "/", Component {} },
+            Route { to: "/blog", Blog {} },
+            Route { to: "/about", Blog {} },
+            Route { to: "/contact", Blog {} },
+            Route { to: "/shop", Blog {} },
+        }
+    })
+}
+```
+
+All Routes must start with a forward slash.
+
+To have dynamic route segments, use the `:id` syntax. If concrete paths come *before* the dynamic syntax, then those will be chosen first.
+
+```rust
+cx.render(rsx! {
+    Router {
+        Route { to: "/", Component {} },
+        Route { to: "/blog", BlogList {} },
+        Route { to: "/blog/welcome", BlogWelcome {} },
+        Route { to: "/blog/:post", BlogPost {} },
+    }
+})
+```
+
+### Nested `Routes`
+
+Routes can be composed at various levels, so you don't just need top-level routes. To do this, simple add Routes inside other Routes
+
+```rust
+cx.render(rsx! {
+    Router {
+        Route { to: "/", Component {} },
+        Route { to: "/blog",
+            BlogContainer {
+                h1 { "blog" } // always renders as long as we're on the "blog" subroute
+                Route { to: "/", BlogList {} }
+                Route { to: "welcome", BlogWelcome {} }
+                Route { to: ":post", BlogPost {} }
+            }
+        },
+    }
+})
+```
+
+### Navigating with `Links`
+
+To navigate your app, regular, old, `a` tags are not going to work. We provide the `Link` component that wraps an `a` tag with the appropriate `href` attribute that generates semantic HTML. You can pass any children into this component and they will become clickable to the appropriate route.
+
+```rust
+Link { to: "/blog/welcome",
+    h1 { "Welcome to my blog!" }
+}
+```
+
+### Segments
+
+Each route in your app is comprised of segments and queries. Segments are the portions of the route delimited by forward slashes.
+
+For the route `/dogs/breeds/yorkie/hugo` our "segment list" would be:
+
+```rust
+vec!["dogs", "breeds", "yorkie", "hugo"]
+```
+
+For any route, you can get a handle the current route with the `use_route` hook.
+
+```rust
+fn Title(cx: Scope) -> Element {
+    let route = use_route(&cx);
+
+    assert_eq!(route.segments(), &["dogs", "breeds", "yorkie", "hugo"]);
+
+    assert_eq!(route.nth_segment(1), "breeds");
+
+    assert_eq!(route.last_segment(), "hugo");
+}
+```
+
+As we've shown above, segments can also be named. We can get these named segments out by the last match at that route level:
+
+```rust
+// For this router:
+Router {
+    Route { to: "/", Component {} },
+    Route { to: "/blog", BlogList {} },
+    Route { to: "/blog/:post", BlogPost {} },
+}
+
+fn BlogPost(cx: Scope) -> Element {
+    let route = use_route(&cx);
+
+    match route.segment("post").and_then(parse) {
+        Some(post) => cx.render(rsx!{ div { "Post {post}" } })
+        None => cx.render(rsx!{ div { "Could not find that blog post" } }),
+    }
+}
+```
+
+
+### Queries
+
+
+
+
+### Listeners
+
+It's possible to connect to route change events from the router by attaching a listener to the Router's `onchange` parameter. This listener is guaranteed to run before any of your routes are matched, so you can perform redirects, add some logging, fetch some data, or do anything that you might want to be synchronous with clicks on Links.
+
+```rust
+fn app() {
+    cx.render(rsx! {
+        Router {
+            onchange: move |router| {
+                let current = router.current_route();
+                log::debug!("App has navigated to {:?}", current);
+
+                // perform a redirect
+                if current == "404" {
+                    router.navigate_to("/");
+                }
+            },
+            Route { to: "/", Component {} },
+        }
+    })
+}
+```
+
+
+Listeners can also be attached downstream in your app with the `RouteListener` handler component:
+
+```rust
+fn TitleCard(cx: Scope) -> Element {
+    let (title, set_title) = use_state(&cx, || "First");
+
+    cx.render(rsx!{
+        h1 { "render {title}" }
+
+        RouteListener { onchange: move |_| set_title("Last") }
+    })
+}
+```
+
+
+### Working with Github Pages and other static hosts
+
+Most "static" hosts will have issues with single-page-app (SPA) routers. To get around this, you can either generate an index.html for each route or hijack the 404 page.
+
+For generating a static index.html, see `Generating a Route List`.
+
+To hijack the 404 page, we can simply make a copy of our index.html page and call it 404.html. When Github Pages serves this 404 page, your app will be served instead and the router will render the right corresponding route.
+
+https://docs.github.com/en/pages/getting-started-with-github-pages/creating-a-custom-404-page-for-your-github-pages-site
+
+### Generating a SiteMap or Route List
+
+If you want to statically generate and rehydrate all your pages, lean on Dioxus Router to do the heavy lifting.
+
+For this feature to work properly, each route (and nested) route will need to be probed, but this can be done automatically.
+
+```rust
+let mut dom = VirtualDom::new(app);
+dom.inject_root_context(RouterContext::new());
+
+// populate the router
+let _ = dom.rebuild();
+
+// load the router context from the dom, generate a sitemap, and then pre-render each page
+let mut prerendered_pages = dom
+    .consume_root_context::<RouterContext>()
+    .unwrap()
+    .sitemap()
+    .into_iter()
+    .map(|route| {
+        // update the root context
+        router.navigate_to(route);
+
+        // force our app to update
+        let _ = dom.rebuild();
+
+        // render the page and insert it into our map
+        (route, dioxus::ssr::render_vdom(&dom))
+    })
+    .collect::<HashMap<_, _>>();
+```