main.rs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. //! Run with:
  2. //!
  3. //! ```sh
  4. //! dioxus build --features web
  5. //! cargo run --features ssr --no-default-features
  6. //! ```
  7. #![allow(non_snake_case)]
  8. use dioxus::prelude::*;
  9. use dioxus_router::*;
  10. use dioxus_server::prelude::*;
  11. use serde::{Deserialize, Serialize};
  12. fn main() {
  13. #[cfg(feature = "web")]
  14. dioxus_web::launch_with_props(
  15. App,
  16. AppProps { route: None },
  17. dioxus_web::Config::new().hydrate(true),
  18. );
  19. #[cfg(feature = "ssr")]
  20. {
  21. use axum::extract::State;
  22. PostServerData::register().unwrap();
  23. GetServerData::register().unwrap();
  24. tokio::runtime::Runtime::new()
  25. .unwrap()
  26. .block_on(async move {
  27. let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080));
  28. use tower_http::services::ServeDir;
  29. // Serve the dist/assets folder with the javascript and WASM files created by the CLI
  30. let serve_dir = ServeDir::new("dist/assets");
  31. axum::Server::bind(&addr)
  32. .serve(
  33. axum::Router::new()
  34. // Register server functions
  35. .register_server_fns("")
  36. // Serve the static assets folder
  37. .nest_service("/assets", serve_dir)
  38. // If the path is unknown, render the application
  39. .fallback(
  40. move |uri: http::uri::Uri, State(ssr_state): State<SSRState>| {
  41. let rendered = ssr_state.render(
  42. &ServeConfigBuilder::new(
  43. App,
  44. AppProps {
  45. route: Some(format!("http://{addr}{uri}")),
  46. },
  47. )
  48. .build(),
  49. );
  50. async move { axum::body::Full::from(rendered) }
  51. },
  52. )
  53. .with_state(SSRState::default())
  54. .into_make_service(),
  55. )
  56. .await
  57. .unwrap();
  58. });
  59. }
  60. }
  61. #[derive(Clone, Debug, Props, PartialEq, Serialize, Deserialize)]
  62. struct AppProps {
  63. route: Option<String>,
  64. }
  65. fn App(cx: Scope<AppProps>) -> Element {
  66. cx.render(rsx! {
  67. Router {
  68. initial_url: cx.props.route.clone(),
  69. Route { to: "/blog",
  70. Link {
  71. to: "/",
  72. "Go to counter"
  73. }
  74. table {
  75. tbody {
  76. for _ in 0..100 {
  77. tr {
  78. for _ in 0..100 {
  79. td { "hello world!" }
  80. }
  81. }
  82. }
  83. }
  84. }
  85. },
  86. // Fallback
  87. Route { to: "",
  88. Counter {}
  89. },
  90. }
  91. })
  92. }
  93. fn Counter(cx: Scope) -> Element {
  94. let mut count = use_state(cx, || 0);
  95. let text = use_state(cx, || "...".to_string());
  96. cx.render(rsx! {
  97. Link {
  98. to: "/blog",
  99. "Go to blog"
  100. }
  101. div{
  102. h1 { "High-Five counter: {count}" }
  103. button { onclick: move |_| count += 1, "Up high!" }
  104. button { onclick: move |_| count -= 1, "Down low!" }
  105. button {
  106. onclick: move |_| {
  107. to_owned![text];
  108. async move {
  109. if let Ok(data) = get_server_data().await {
  110. println!("Client received: {}", data);
  111. text.set(data.clone());
  112. post_server_data(data).await.unwrap();
  113. }
  114. }
  115. },
  116. "Run a server function"
  117. }
  118. "Server said: {text}"
  119. }
  120. })
  121. }
  122. #[server(PostServerData)]
  123. async fn post_server_data(data: String) -> Result<(), ServerFnError> {
  124. println!("Server received: {}", data);
  125. Ok(())
  126. }
  127. #[server(GetServerData)]
  128. async fn get_server_data() -> Result<String, ServerFnError> {
  129. Ok("Hello from the server!".to_string())
  130. }