ソースを参照

finish server function docs

Evan Almloff 2 年 前
コミット
ab1de6e53f

+ 2 - 2
docs/guide/examples/hydration_props.rs

@@ -31,11 +31,11 @@ fn main() {
                             // Render the application. This will serialize the root props (the intial count) into the HTML
                             .route(
                                 "/",
-                                get(move |Path(intial_count): Path<usize>, State(ssr_state): State<SSRState>| async move { axum::body::Full::from(
+                                get(move | State(ssr_state): State<SSRState>| async move { axum::body::Full::from(
                                     ssr_state.render(
                                         &ServeConfigBuilder::new(
                                             app,
-                                            intial_count,
+                                            0,
                                         )
                                         .build(),
                                     )

+ 18 - 5
docs/guide/examples/server_context.rs

@@ -35,11 +35,11 @@ fn main() {
                             // Render the application. This will serialize the root props (the intial count) into the HTML
                             .route(
                                 "/",
-                                get(move |Path(intial_count): Path<usize>, State(ssr_state): State<SSRState>| async move { axum::body::Full::from(
+                                get(move |State(ssr_state): State<SSRState>| async move { axum::body::Full::from(
                                     ssr_state.render(
                                         &ServeConfigBuilder::new(
                                             app,
-                                            intial_count,
+                                            0,
                                         )
                                         .build(),
                                     )
@@ -77,9 +77,10 @@ fn app(cx: Scope<usize>) -> Element {
         button {
             onclick: move |_| {
                 to_owned![count];
+                let sc = cx.sc();
                 async move {
                     // Call the server function just like a local async function
-                    if let Ok(new_count) = double_server(*count.current()).await {
+                    if let Ok(new_count) = double_server(sc, *count.current()).await {
                         count.set(new_count);
                     }
                 }
@@ -89,11 +90,23 @@ fn app(cx: Scope<usize>) -> Element {
     })
 }
 
-#[server(DoubleServer)]
-async fn double_server(number: usize) -> Result<usize, ServerFnError> {
+// We use the "getcbor" encoding to make caching easier
+#[server(DoubleServer, "", "getcbor")]
+async fn double_server(cx: DioxusServerContext, number: usize) -> Result<usize, ServerFnError> {
     // Perform some expensive computation or access a database on the server
     tokio::time::sleep(std::time::Duration::from_secs(1)).await;
     let result = number * 2;
+
+    println!(
+        "User Agent {:?}",
+        cx.request_parts().headers.get("User-Agent")
+    );
+
+    // Set the cache control header to 1 hour on the post request
+    cx.responce_headers_mut()
+        .insert("Cache-Control", "max-age=3600".parse().unwrap());
+
     println!("server calculated {result}");
+
     Ok(result)
 }

+ 137 - 0
docs/guide/examples/server_context_state.rs

@@ -0,0 +1,137 @@
+#![allow(non_snake_case, unused)]
+use dioxus::prelude::*;
+use dioxus_fullstack::prelude::*;
+
+#[cfg(feature = "ssr")]
+#[derive(Default, Clone)]
+struct ServerFunctionState {
+    call_count: std::sync::Arc<std::sync::atomic::AtomicUsize>,
+}
+
+fn main() {
+    #[cfg(feature = "web")]
+    dioxus_web::launch_with_props(
+        app,
+        // Get the root props from the document
+        get_root_props_from_document().unwrap_or_default(),
+        dioxus_web::Config::new().hydrate(true),
+    );
+    #[cfg(feature = "ssr")]
+    {
+        use axum::body::Body;
+        use axum::extract::Path;
+        use axum::extract::State;
+        use axum::http::Request;
+        use axum::routing::get;
+        use std::sync::Arc;
+
+        // Register the server function before starting the server
+        DoubleServer::register().unwrap();
+
+        tokio::runtime::Runtime::new()
+            .unwrap()
+            .block_on(async move {
+                let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080));
+                axum::Server::bind(&addr)
+                    .serve(
+                        axum::Router::new()
+                            // Serve the dist folder with the static javascript and WASM files created by the dixous CLI
+                            .serve_static_assets("./dist")
+                            // Register server functions
+                            .register_server_fns_with_handler("", |func| {
+                                move |State(server_fn_state): State<ServerFunctionState>, req: Request<Body>| async move {
+                                    let (parts, body) = req.into_parts();
+                                    let parts: Arc<RequestParts> = Arc::new(parts.into());
+                                    let mut server_context = DioxusServerContext::new(parts.clone());
+                                    server_context.insert(server_fn_state);
+                                    server_fn_handler(server_context, func.clone(), parts, body).await
+                                }
+                            })
+                            .with_state(ServerFunctionState::default())
+                            // Connect to the hot reload server in debug mode
+                            .connect_hot_reload()
+                            // Render the application. This will serialize the root props (the intial count) into the HTML
+                            .route(
+                                "/",
+                                get(move |State(ssr_state): State<SSRState>| async move { axum::body::Full::from(
+                                    ssr_state.render(
+                                        &ServeConfigBuilder::new(
+                                            app,
+                                            0,
+                                        )
+                                        .build(),
+                                    )
+                                )}),
+                            )
+                            // Render the application with a different intial count
+                            .route(
+                                "/:initial_count",
+                                get(move |Path(intial_count): Path<usize>, State(ssr_state): State<SSRState>| async move { axum::body::Full::from(
+                                    ssr_state.render(
+                                        &ServeConfigBuilder::new(
+                                            app,
+                                            intial_count,
+                                        )
+                                        .build(),
+                                    )
+                                )}),
+                            )
+                            .with_state(SSRState::default())
+                            .into_make_service(),
+                    )
+                    .await
+                    .unwrap();
+            });
+    }
+}
+
+fn app(cx: Scope<usize>) -> Element {
+    let mut count = use_state(cx, || *cx.props);
+
+    cx.render(rsx! {
+        h1 { "High-Five counter: {count}" }
+        button { onclick: move |_| count += 1, "Up high!" }
+        button { onclick: move |_| count -= 1, "Down low!" }
+        button {
+            onclick: move |_| {
+                to_owned![count];
+                let sc = cx.sc();
+                async move {
+                    // Call the server function just like a local async function
+                    if let Ok(new_count) = double_server(sc, *count.current()).await {
+                        count.set(new_count);
+                    }
+                }
+            },
+            "Double"
+        }
+    })
+}
+
+// We use the "getcbor" encoding to make caching easier
+#[server(DoubleServer, "", "getcbor")]
+async fn double_server(cx: DioxusServerContext, number: usize) -> Result<usize, ServerFnError> {
+    // Perform some expensive computation or access a database on the server
+    tokio::time::sleep(std::time::Duration::from_secs(1)).await;
+    let result = number * 2;
+
+    println!(
+        "User Agent {:?}",
+        cx.request_parts().headers.get("User-Agent")
+    );
+
+    // Set the cache control header to 1 hour on the post request
+    cx.responce_headers_mut()
+        .insert("Cache-Control", "max-age=3600".parse().unwrap());
+
+    // Get the server function state
+    let server_fn_state = cx.get::<ServerFunctionState>().unwrap();
+    let call_count = server_fn_state
+        .call_count
+        .fetch_add(1, std::sync::atomic::Ordering::SeqCst);
+    println!("server functions have been called {call_count} times");
+
+    println!("server calculated {result}");
+
+    Ok(result)
+}

+ 6 - 4
packages/fullstack/src/adapters/axum_adapter.rs

@@ -91,9 +91,11 @@ pub trait DioxusRouterExt<S> {
     ///        .serve(
     ///            axum::Router::new()
     ///                .register_server_fns_with_handler("", |func| {
-    ///                    move |headers: HeaderMap, body: Request<Body>| async move {
-    ///                        // Add the headers to the context
-    ///                        server_fn_handler((headers.clone(),), func.clone(), headers, body).await
+    ///                    move |req: Request<Body>| async move {
+    ///                        let (parts, body) = req.into_parts();
+    ///                        let parts: Arc<RequestParts> = Arc::new(parts.into());
+    ///                        let server_context = DioxusServerContext::new(parts.clone());
+    ///                        server_fn_handler(server_context, func.clone(), parts, body).await
     ///                    }
     ///                })
     ///                .into_make_service(),
@@ -366,7 +368,7 @@ async fn render_handler<P: Clone + serde::Serialize + Send + Sync + 'static>(
     Full::from(rendered)
 }
 
-/// A default handler for server functions. It will deserialize the request body, call the server function, and serialize the response.
+/// A default handler for server functions. It will deserialize the request, call the server function, and serialize the response.
 pub async fn server_fn_handler(
     server_context: DioxusServerContext,
     function: ServerFunction,