codify "platform" into resolution logic, server-fn/fullstack overhaul (#4596)
overhaul dioxus fullstack using a new implementation of server_fn This PR is a complete rewrite of dioxus fullstack designed to improve compatibility with axum and to fix a number of compilation errors based on feature flag unification plumbing through macros.
This commit is contained in:
1 parent
8421c3aef0
commit
f2b1c6d97f
424 files changed
+17284
-6624
No files matched your search
@@ -0,0 +1,65 @@
|
||||
//! Backgrounded futures example
|
||||
//!
|
||||
//! This showcases how use_future, use_memo, and use_effect will stop running if the component returns early.
|
||||
//! Generally you should avoid using early returns around hooks since most hooks are not properly designed to
|
||||
//! handle early returns. However, use_future *does* pause the future when the component returns early, and so
|
||||
//! hooks that build on top of it like use_memo and use_effect will also pause.
|
||||
//!
|
||||
//! This example is more of a demonstration of the behavior than a practical use case, but it's still interesting to see.
|
||||
|
||||
use async_std::task::sleep;
|
||||
use dioxus::prelude::*;
|
||||
|
||||
fn main() {
|
||||
dioxus::launch(app);
|
||||
}
|
||||
|
||||
fn app() -> Element {
|
||||
let mut show_child = use_signal(|| true);
|
||||
let mut count = use_signal(|| 0);
|
||||
|
||||
let child = use_memo(move || {
|
||||
rsx! {
|
||||
Child { count }
|
||||
}
|
||||
});
|
||||
|
||||
rsx! {
|
||||
// Some toggle/controls to show the child or increment the count
|
||||
button { onclick: move |_| show_child.toggle(), "Toggle child" }
|
||||
button { onclick: move |_| count += 1, "Increment count" }
|
||||
|
||||
if show_child() {
|
||||
{child()}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[component]
|
||||
fn Child(count: WriteSignal<i32>) -> Element {
|
||||
let mut early_return = use_signal(|| false);
|
||||
|
||||
let early = rsx! {
|
||||
button { onclick: move |_| early_return.toggle(), "Toggle {early_return} early return" }
|
||||
};
|
||||
|
||||
if early_return() {
|
||||
return early;
|
||||
}
|
||||
|
||||
use_future(move || async move {
|
||||
loop {
|
||||
sleep(std::time::Duration::from_millis(100)).await;
|
||||
println!("Child")
|
||||
}
|
||||
});
|
||||
|
||||
use_effect(move || println!("Child count: {}", count()));
|
||||
|
||||
rsx! {
|
||||
div {
|
||||
"Child component"
|
||||
{early}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
//! A simple little clock that updates the time every few milliseconds.
|
||||
|
||||
use async_std::task::sleep;
|
||||
use dioxus::prelude::*;
|
||||
use web_time::Instant;
|
||||
|
||||
fn main() {
|
||||
dioxus::launch(app);
|
||||
}
|
||||
|
||||
fn app() -> Element {
|
||||
let mut millis = use_signal(|| 0);
|
||||
|
||||
use_future(move || async move {
|
||||
// Save our initial time
|
||||
let start = Instant::now();
|
||||
|
||||
loop {
|
||||
sleep(std::time::Duration::from_millis(27)).await;
|
||||
|
||||
// Update the time, using a more precise approach of getting the duration since we started the timer
|
||||
millis.set(start.elapsed().as_millis() as i64);
|
||||
}
|
||||
});
|
||||
|
||||
// Format the time as a string
|
||||
// This is rather cheap so it's fine to leave it in the render function
|
||||
let time = format!(
|
||||
"{:02}:{:02}:{:03}",
|
||||
millis() / 1000 / 60 % 60,
|
||||
millis() / 1000 % 60,
|
||||
millis() % 1000
|
||||
);
|
||||
|
||||
rsx! {
|
||||
document::Stylesheet { href: asset!("/examples/assets/clock.css") }
|
||||
div { id: "app",
|
||||
div { id: "title", "Carpe diem 🎉" }
|
||||
div { id: "clock-display", "{time}" }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
//! A simple example that shows how to use the use_future hook to run a background task.
|
||||
//!
|
||||
//! use_future won't return a value, analogous to use_effect.
|
||||
//! If you want to return a value from a future, use use_resource instead.
|
||||
|
||||
use async_std::task::sleep;
|
||||
use dioxus::prelude::*;
|
||||
|
||||
fn main() {
|
||||
dioxus::launch(app);
|
||||
}
|
||||
|
||||
fn app() -> Element {
|
||||
let mut count = use_signal(|| 0);
|
||||
|
||||
// use_future is a non-reactive hook that simply runs a future in the background.
|
||||
// You can use the UseFuture handle to pause, resume, restart, or cancel the future.
|
||||
use_future(move || async move {
|
||||
loop {
|
||||
sleep(std::time::Duration::from_millis(200)).await;
|
||||
count += 1;
|
||||
}
|
||||
});
|
||||
|
||||
// use_effect is a reactive hook that runs a future when signals captured by its reactive context
|
||||
// are modified. This is similar to use_effect in React and is useful for running side effects
|
||||
// that depend on the state of your component.
|
||||
//
|
||||
// Generally, we recommend performing async work in event as a reaction to a user event.
|
||||
use_effect(move || {
|
||||
spawn(async move {
|
||||
sleep(std::time::Duration::from_secs(5)).await;
|
||||
count.set(100);
|
||||
});
|
||||
});
|
||||
|
||||
// You can run futures directly from event handlers as well. Note that if the event handler is
|
||||
// fired multiple times, the future will be spawned multiple times.
|
||||
rsx! {
|
||||
h1 { "Current count: {count}" }
|
||||
button {
|
||||
onclick: move |_| async move {
|
||||
sleep(std::time::Duration::from_millis(200)).await;
|
||||
count.set(0);
|
||||
},
|
||||
"Slowly reset the count"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
//! Handle async streams using use_future and awaiting the next value.
|
||||
|
||||
use async_std::task::sleep;
|
||||
use dioxus::prelude::*;
|
||||
use futures_util::{Stream, StreamExt, future, stream};
|
||||
|
||||
fn main() {
|
||||
dioxus::launch(app);
|
||||
}
|
||||
|
||||
fn app() -> Element {
|
||||
let mut count = use_signal(|| 10);
|
||||
|
||||
use_future(move || async move {
|
||||
// Create the stream.
|
||||
// This could be a network request, a file read, or any other async operation.
|
||||
let mut stream = some_stream();
|
||||
|
||||
// Await the next value from the stream.
|
||||
while let Some(second) = stream.next().await {
|
||||
count.set(second);
|
||||
}
|
||||
});
|
||||
|
||||
rsx! {
|
||||
h1 { "High-Five counter: {count}" }
|
||||
}
|
||||
}
|
||||
|
||||
fn some_stream() -> std::pin::Pin<Box<dyn Stream<Item = i32>>> {
|
||||
Box::pin(
|
||||
stream::once(future::ready(0)).chain(stream::iter(1..).then(|second| async move {
|
||||
sleep(std::time::Duration::from_secs(1)).await;
|
||||
second
|
||||
})),
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
//! Suspense in Dioxus
|
||||
//!
|
||||
//! Suspense allows components to bubble up loading states to parent components, simplifying data fetching.
|
||||
|
||||
use dioxus::prelude::*;
|
||||
|
||||
fn main() {
|
||||
dioxus::launch(app)
|
||||
}
|
||||
|
||||
fn app() -> Element {
|
||||
rsx! {
|
||||
div {
|
||||
h1 { "Dogs are very important" }
|
||||
p {
|
||||
"The dog or domestic dog (Canis familiaris[4][5] or Canis lupus familiaris[5])"
|
||||
"is a domesticated descendant of the wolf which is characterized by an upturning tail."
|
||||
"The dog derived from an ancient, extinct wolf,[6][7] and the modern grey wolf is the"
|
||||
"dog's nearest living relative.[8] The dog was the first species to be domesticated,[9][8]"
|
||||
"by hunter–gatherers over 15,000 years ago,[7] before the development of agriculture.[1]"
|
||||
}
|
||||
h3 { "Illustrious Dog Photo" }
|
||||
ErrorBoundary { handle_error: |_| rsx! { p { "Error loading doggos" } },
|
||||
SuspenseBoundary { fallback: move |_| rsx! { "Loading doggos..." },
|
||||
Doggo {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[component]
|
||||
fn Doggo() -> Element {
|
||||
// `use_loader` returns a Result<Loader<T>, Loading>. Loading can either be "Pending" or "Failed".
|
||||
// When we use the `?` operator, the pending/error state will be thrown to the nearest Suspense or Error boundary.
|
||||
//
|
||||
// During SSR, `use_loader` will serialize the contents of the fetch, and during hydration, the client will
|
||||
// use the pre-fetched data instead of re-fetching to render.
|
||||
let mut dog = use_loader(move || async move {
|
||||
#[derive(serde::Deserialize, serde::Serialize, PartialEq)]
|
||||
struct DogApi {
|
||||
message: String,
|
||||
}
|
||||
|
||||
reqwest::get("https://dog.ceo/api/breeds/image/random/")
|
||||
.await
|
||||
.unwrap()
|
||||
.json::<DogApi>()
|
||||
.await
|
||||
})?;
|
||||
|
||||
rsx! {
|
||||
button { onclick: move |_| dog.restart(), "Click to fetch another doggo" }
|
||||
div {
|
||||
img {
|
||||
max_width: "500px",
|
||||
max_height: "500px",
|
||||
src: "{dog.read().message}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user