Forráskód Böngészése

fix external router examples

Evan Almloff 2 éve
szülő
commit
07446386e6

+ 83 - 71
examples/router.rs

@@ -4,97 +4,109 @@ use dioxus::prelude::*;
 use dioxus_router::prelude::*;
 
 fn main() {
-    dioxus_desktop::launch(app);
+    #[cfg(target_arch = "wasm32")]
+    dioxus_web::launch(App);
+    #[cfg(not(target_arch = "wasm32"))]
+    dioxus_desktop::launch(App);
 }
 
-fn app(cx: Scope) -> Element {
-    use_router(cx, &RouterConfiguration::default, &|| {
-        Segment::content(comp(Home))
-            .fixed(
-                "users",
-                Route::empty()
-                    .nested(Segment::content(comp(UserList)).catch_all((comp(User), UserId {}))),
-            )
-            .fixed(
-                "blog",
-                Route::empty().nested(
-                    Segment::content(comp(BlogList)).catch_all((comp(BlogPost), PostId {})),
-                ),
-            )
-            .fallback(comp(E404))
-    });
-
-    cx.render(rsx! {
-        ul {
-            li { Link { target: "/", "Go home!" } }
-            li { Link { target: "/users", "List all users" } }
-            li { Link { target: "/blog", "Blog posts" }}
-        }
-
-        Outlet { }
-    })
+// ANCHOR: router
+#[derive(Routable, Clone)]
+#[rustfmt::skip]
+enum Route {
+    #[layout(NavBar)]
+        #[route("/")]
+        Home {},
+        #[nest("/blog")]
+            #[layout(Blog)]
+                #[route("/")]
+                BlogList {},
+                #[route("/blog/:name")]
+                BlogPost { name: String },
+            #[end_layout]
+        #[end_nest]
+    #[end_layout]
+    #[nest("/myblog")]
+        #[redirect("/", || Route::BlogList {})]
+        #[redirect("/:name", |name: String| Route::BlogPost { name })]
+    #[end_nest]
+    #[route("/:...route")]
+    PageNotFound {
+        route: Vec<String>,
+    },
 }
+// ANCHOR_END: router
 
-fn Home(cx: Scope) -> Element {
-    render!(h1 { "Home" })
+fn App(cx: Scope) -> Element {
+    render! {
+        Router {}
+    }
 }
 
-fn BlogList(cx: Scope) -> Element {
+#[inline_props]
+fn NavBar(cx: Scope) -> Element {
     render! {
-        h1 { "Blog Posts" }
-        ul {
-            li { Link { target: "/blog/1", "First blog post" } }
-            li { Link { target: "/blog/2", "Second blog post" } }
-            li { Link { target: "/blog/3", "Third blog post" } }
+        nav {
+            ul {
+                li { Link { target: Route::Home {}, "Home" } }
+                li { Link { target: Route::BlogList {}, "Blog" } }
+            }
         }
+        Outlet {}
     }
 }
 
-struct PostId;
-fn BlogPost(cx: Scope) -> Element {
-    let post = use_route(cx)?.parameter::<PostId>().unwrap();
+#[inline_props]
+fn Home(cx: Scope) -> Element {
+    render! {
+        h1 { "Welcome to the Dioxus Blog!" }
+    }
+}
 
-    cx.render(rsx! {
-        div {
-            h1 { "Reading blog post: {post}" }
-            p { "example blog post" }
-        }
-    })
+#[inline_props]
+fn Blog(cx: Scope) -> Element {
+    render! {
+        h1 { "Blog" }
+        Outlet {}
+    }
 }
 
-fn UserList(cx: Scope) -> Element {
+#[inline_props]
+fn BlogList(cx: Scope) -> Element {
     render! {
-        h1 { "Users" }
+        h2 { "Choose a post" }
         ul {
-            li { Link { target: "/users/bill", "Bill" } }
-            li { Link { target: "/users/jeremy", "Jeremy" } }
-            li { Link { target: "/users/adrian", "Adrian" } }
+            li {
+                Link {
+                    target: Route::BlogPost { name: "Blog post 1".into() },
+                    "Read the first blog post"
+                }
+            }
+            li {
+                Link {
+                    target: Route::BlogPost { name: "Blog post 2".into() },
+                    "Read the second blog post"
+                }
+            }
         }
     }
 }
 
-struct UserId;
-fn User(cx: Scope) -> Element {
-    let state = use_route(cx)?;
-
-    let user = state.parameter::<UserId>().unwrap();
-
-    let query = state.query.as_ref().cloned().unwrap_or_default();
-    let bold = query.contains("bold") && !query.contains("bold=false");
-
-    cx.render(rsx! {
-        div {
-            h1 { "Showing user: {user}" }
-
-            if bold {
-                rsx!{ b { "bold" } }
-            } else {
-                rsx!{ i { "italic" } }
-            }
-        }
-    })
+#[inline_props]
+fn BlogPost(cx: Scope, name: String) -> Element {
+    render! {
+        h2 { "Blog Post: {name}"}
+    }
 }
 
-fn E404(cx: Scope) -> Element {
-    render!(h1 { "Error 404 - Page not Found" })
+#[inline_props]
+fn PageNotFound(cx: Scope, route: Vec<String>) -> Element {
+    render! {
+        h1 { "Page not found" }
+        p { "We are terribly sorry, but the page you requested doesn't exist." }
+        pre {
+            color: "red",
+            "log:\nattemped to navigate to: {route:?}"
+        }
+    }
 }

+ 46 - 28
packages/fullstack/examples/axum-router/src/main.rs

@@ -8,7 +8,7 @@
 #![allow(non_snake_case)]
 use dioxus::prelude::*;
 use dioxus_fullstack::prelude::*;
-use dioxus_router::*;
+use dioxus_router::prelude::*;
 use serde::{Deserialize, Serialize};
 
 fn main() {
@@ -34,6 +34,8 @@ fn main() {
         }));
 
         use axum::extract::State;
+        use std::str::FromStr;
+
         PostServerData::register().unwrap();
         GetServerData::register().unwrap();
         tokio::runtime::Runtime::new()
@@ -57,7 +59,7 @@ fn main() {
                                         &ServeConfigBuilder::new(
                                             App,
                                             AppProps {
-                                                route: Some(format!("http://{addr}{uri}")),
+                                                route: Route::from_str(&uri.to_string()).ok(),
                                             },
                                         )
                                         .build(),
@@ -74,48 +76,64 @@ fn main() {
     }
 }
 
+#[derive(Clone, Routable, Serialize, Deserialize, Debug, PartialEq)]
+enum Route {
+    #[route("/")]
+    Home {},
+    #[route("/blog")]
+    Blog {},
+}
+
+#[inline_props]
+fn Blog(cx: Scope) -> Element {
+    render! {
+        Link {
+            target: Route::Home {},
+            "Go to counter"
+        }
+        table {
+            tbody {
+                for _ in 0..100 {
+                    tr {
+                        for _ in 0..100 {
+                            td { "hello world!" }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
 #[derive(Clone, Debug, Props, PartialEq, Serialize, Deserialize)]
 struct AppProps {
-    route: Option<String>,
+    route: Option<Route>,
 }
 
 fn App(cx: Scope<AppProps>) -> Element {
+    #[cfg(feature = "ssr")]
+    let initial_route = cx.props.route.clone().unwrap_or(Route::Home {});
     cx.render(rsx! {
         Router {
-            initial_url: cx.props.route.clone(),
-
-            Route { to: "/blog",
-                Link {
-                    to: "/",
-                    "Go to counter"
-                }
-                table {
-                    tbody {
-                        for _ in 0..100 {
-                            tr {
-                                for _ in 0..100 {
-                                    td { "hello world!" }
-                                }
-                            }
-                        }
-                    }
-                }
-            },
-            // Fallback
-            Route { to: "",
-                Counter {}
-            },
+            config: move || RouterConfig::default().history({
+                #[cfg(feature = "ssr")]
+                let history = MemoryHistory::with_initial_path(initial_route);
+                #[cfg(feature = "web")]
+                let history = WebHistory::default();
+                history
+            })
         }
     })
 }
 
-fn Counter(cx: Scope) -> Element {
+#[inline_props]
+fn Home(cx: Scope) -> Element {
     let mut count = use_state(cx, || 0);
     let text = use_state(cx, || "...".to_string());
 
     cx.render(rsx! {
         Link {
-            to: "/blog",
+            target: Route::Blog {}
             "Go to blog"
         }
         div{

+ 4 - 6
packages/router/src/components/router.rs

@@ -5,13 +5,13 @@ use std::{cell::RefCell, str::FromStr};
 use crate::{
     prelude::{GenericOutlet, GenericRouterContext},
     routable::Routable,
-    router_cfg::RouterConfiguration,
+    router_cfg::RouterConfig,
 };
 
 /// The config for [`GenericRouter`].
 pub struct RouterConfigFactory<R: Routable> {
     #[allow(clippy::type_complexity)]
-    config: RefCell<Option<Box<dyn FnOnce() -> RouterConfiguration<R>>>>,
+    config: RefCell<Option<Box<dyn FnOnce() -> RouterConfig<R>>>>,
 }
 
 impl<R: Routable> Default for RouterConfigFactory<R>
@@ -19,13 +19,11 @@ where
     <R as FromStr>::Err: std::fmt::Display,
 {
     fn default() -> Self {
-        Self::from(RouterConfiguration::default)
+        Self::from(RouterConfig::default)
     }
 }
 
-impl<R: Routable, F: FnOnce() -> RouterConfiguration<R> + 'static> From<F>
-    for RouterConfigFactory<R>
-{
+impl<R: Routable, F: FnOnce() -> RouterConfig<R> + 'static> From<F> for RouterConfigFactory<R> {
     fn from(value: F) -> Self {
         Self {
             config: RefCell::new(Some(Box::new(value))),

+ 4 - 6
packages/router/src/contexts/router.rs

@@ -7,7 +7,7 @@ use dioxus::prelude::*;
 
 use crate::{
     history::HistoryProvider, navigation::NavigationTarget, routable::Routable,
-    router_cfg::RouterConfiguration,
+    router_cfg::RouterConfig,
 };
 
 /// An error that can occur when navigating.
@@ -15,7 +15,8 @@ use crate::{
 pub struct ExternalNavigationFailure(String);
 
 /// A function the router will call after every routing update.
-pub(crate) type RoutingCallback<R> = Arc<dyn Fn(GenericRouterContext<R>) -> Option<NavigationTarget<R>>>;
+pub(crate) type RoutingCallback<R> =
+    Arc<dyn Fn(GenericRouterContext<R>) -> Option<NavigationTarget<R>>>;
 
 struct MutableRouterState<R>
 where
@@ -70,10 +71,7 @@ impl<R> GenericRouterContext<R>
 where
     R: Routable,
 {
-    pub(crate) fn new(
-        cfg: RouterConfiguration<R>,
-        mark_dirty: Arc<dyn Fn(ScopeId) + Sync + Send>,
-    ) -> Self
+    pub(crate) fn new(cfg: RouterConfig<R>, mark_dirty: Arc<dyn Fn(ScopeId) + Sync + Send>) -> Self
     where
         R: Clone,
     {

+ 5 - 7
packages/router/src/history/memory.rs

@@ -33,17 +33,15 @@ where
     ///     OtherPage {},
     /// }
     ///
-    /// let mut history = MemoryHistory::<Route>::with_initial_path("/").unwrap();
+    /// let mut history = MemoryHistory::<Route>::with_initial_path(Route::Index {}).unwrap();
     /// assert_eq!(history.current_route(), Route::Index {});
     /// assert_eq!(history.can_go_back(), false);
     /// ```
-    pub fn with_initial_path(path: impl AsRef<str>) -> Result<Self, <R as FromStr>::Err> {
-        let path = path.as_ref();
-
-        Ok(Self {
-            current: R::from_str(path)?,
+    pub fn with_initial_path(path: R) -> Self {
+        Self {
+            current: path,
             ..Default::default()
-        })
+        }
     }
 }
 

+ 1 - 1
packages/router/src/lib.rs

@@ -56,7 +56,7 @@ pub mod prelude {
     pub use crate::hooks::*;
     pub use crate::navigation::*;
     pub use crate::routable::*;
-    pub use crate::router_cfg::RouterConfiguration;
+    pub use crate::router_cfg::RouterConfig;
     pub use dioxus_router_macro::Routable;
 
     #[doc(hidden)]

+ 4 - 4
packages/router/src/router_cfg.rs

@@ -23,15 +23,15 @@ use crate::prelude::*;
 ///     #[route("/")]
 ///     Index {},
 /// }
-/// let cfg = RouterConfiguration::default().history(WebHistory<Route>::default());
+/// let cfg = RouterConfig::default().history(WebHistory<Route>::default());
 /// ```
-pub struct RouterConfiguration<R: Routable> {
+pub struct RouterConfig<R: Routable> {
     pub(crate) failure_external_navigation: fn(Scope) -> Element,
     pub(crate) history: Box<dyn HistoryProvider<R>>,
     pub(crate) on_update: Option<RoutingCallback<R>>,
 }
 
-impl<R: Routable + Clone> Default for RouterConfiguration<R>
+impl<R: Routable + Clone> Default for RouterConfig<R>
 where
     <R as std::str::FromStr>::Err: std::fmt::Display,
 {
@@ -50,7 +50,7 @@ where
     }
 }
 
-impl<R: Routable> RouterConfiguration<R> {
+impl<R: Routable> RouterConfig<R> {
     /// A function to be called whenever the routing is updated.
     ///
     /// The callback is invoked after the routing is updated, but before components and hooks are