Comments (13)
use_server_future
suspends the component here:
let recipe = use_server_future(move || {
get_recipe(id.clone())
})?;
The ?
will return None (and render a placeholder) when the future is resolving. We don't do a full reload of the page because it generally won't make the future resolve any faster and it would reset the state in your page.
Suspense boundaries are not implemented yet, but once they are you will be able to handle rendering a placeholder higher up in your component.
from dioxus.
To be more exact the version I'm using is
dioxus = { git = "https://github.com/ealmloff/dioxus.git", branch = "fix-fullstack-history"
since routing was broken in 0.5.0 alpha.
from dioxus.
Also would be great to have more debug logging in Dioxus, to better see what's going on under the hood when something like this happens.
from dioxus.
It's always the last rsx expression that gets sent over the websocket when anything changes. So changing the order of match clauses will change the behavior.
from dioxus.
If you set DIOXUS_LOG="trace"
, the CLI will log some information about what it thought changed between the new and old versions of the code.
Some part of the code diffing rsx here may be broken:
dioxus/packages/rsx/src/hot_reload/hot_reload_diff.rs
Lines 455 to 481 in 9ae3d14
I was unable to reproduce this issue with the CLI version installed from the latest commit on the main
branch (9ae3d14) and the fix-fullstack-history
branch of dioxus on either the web platform or the fullstack platform on MacOs with this code:
use dioxus::prelude::*;
fn main() {
launch(app);
}
fn app() -> Element {
rsx! {
RecipeView { id: "1".to_string() }
}
}
#[component]
pub fn RecipeView(id: String) -> Element {
let recipe: Option<Result<usize, usize>> = Some(Ok(1));
match recipe {
Some(Ok(recipe)) => {
rsx! {
div { class: "flex flex-col justify-center overflow-hidden py-6",
div { class: "mx-auto max-w-2xl",
h1 { class: "text-5xl text-center font-extrabold py-3", "{recipe}" }
p { class: "text-4xl py-3", "{recipe}" }
p { "Another static text with more data" }
}
}
}
}
Some(Err(_)) => {
rsx! {"Error loading recipe"}
}
None => {
rsx! {"Loading..."}
}
}
}
from dioxus.
Maybe in your code example the compiler optimizes the other cases away, since you have a static value 😊
If I try with DIOXUS_LOG
in trace level, I run into another problem which is the hot_reload
websocket getting closed early. Also I get this flood of continuous log messages in the terminal that never stop. Keeps the CPU busy
[TRACE] dfs_in_order: visit_instr(Store(Store { memory: Id { idx: 0 }, kind: I32 { atomic: false }, arg: MemArg { align: 4, offset: 4 } }))
[TRACE] dfs_in_order: (Store(Store { memory: Id { idx: 0 }, kind: I32 { atomic: false }, arg: MemArg { align: 4, offset: 4 } })).visit(..)
[TRACE] dfs_in_order: visit_instr(LocalGet(LocalGet { local: Id { idx: 312841 } }))
[TRACE] dfs_in_order: (LocalGet(LocalGet { local: Id { idx: 312841 } })).visit(..)
[TRACE] dfs_in_order: visit_instr(Load(Load { memory: Id { idx: 0 }, kind: I32 { atomic: false }, arg: MemArg { align: 4, offset: 4 } }))
[TRACE] dfs_in_order: (Load(Load { memory: Id { idx: 0 }, kind: I32 { atomic: false }, arg: MemArg { align: 4, offset: 4 } })).visit(..)
[TRACE] dfs_in_order: visit_instr(LocalSet(LocalSet { local: Id { idx: 312856 } }))
[TRACE] dfs_in_order: (LocalSet(LocalSet { local: Id { idx: 312856 } })).visit(..)
[TRACE] dfs_in_order: visit_instr(Const(Const { value: I32(32) }))
[TRACE] dfs_in_order: (Const(Const { value: I32(32) })).visit(..)
from dioxus.
Actually it seems like those two cases don't ever get to produce a template. When I force a long delay on the server call, I can see in the browser inspector that the component contents for None
case is never inserted into the DOM. It just has some <pre hidden></pre>
placeholder there.
from dioxus.
Another weird thing I'm seeing in the logs is the execution of part of the server function multiple times.
[INFO] dioxus_fullstack::render - Suspense resolved
get_recipe: done
[INFO] dioxus_core::diff::node - creating template self=VNode { vnode: VNodeInner { key: None, template: Cell { value: Template { name: "src/components/recipe.rs:19:13:2484", roots: [Element { tag: "div", namespace: None, attrs: [Static { name: "class", value: "flex flex-col justify-center overflow-hidden py-6", namespace: None }], children: [Element { tag: "div", namespace: None, attrs: [Static { name: "class", value: "mx-auto max-w-2xl", namespace: None }], children: [Element { tag: "h1", namespace: None, attrs: [Static { name: "class", value: "text-5xl text-center font-extrabold py-3", namespace: None }], children: [DynamicText { id: 0 }] }, Element { tag: "p", namespace: None, attrs: [Static { name: "class", value: "text-xl py-3", namespace: None }], children: [DynamicText { id: 1 }] }, Element { tag: "p", namespace: None, attrs: [], children: [Text { text: "Another static text with more datas" }] }] }] }], node_paths: [[0, 0, 0, 0], [0, 0, 1, 0]], attr_paths: [] } }, dynamic_nodes: [Text(VText { value: "Test Recipe" }), Text(VText { value: "This is a test recipe" })], dynamic_attrs: [] }, mount: Cell { value: MountId(4) } } mount=MountId(4)
[INFO] dioxus_fullstack::render - Suspense resolved
spinning up hot reloading
hot reloading ready
🔥 Hot Reload WebSocket connected
Connected to hot reloading 🚀
🔮 Finding updates since last compile...
finished
get_recipe: done
[INFO] dioxus_core::diff::node - creating template self=VNode { vnode: VNodeInner { key: None, template: Cell { value: Template { name: "src/components/recipe.rs:19:13:2484", roots: [Element { tag: "div", namespace: None, attrs: [Static { name: "class", value: "flex flex-col justify-center overflow-hidden py-6", namespace: None }], children: [Element { tag: "div", namespace: None, attrs: [Static { name: "class", value: "mx-auto max-w-2xl", namespace: None }], children: [Element { tag: "h1", namespace: None, attrs: [Static { name: "class", value: "text-5xl text-center font-extrabold py-3", namespace: None }], children: [DynamicText { id: 0 }] }, Element { tag: "p", namespace: None, attrs: [Static { name: "class", value: "text-xl py-3", namespace: None }], children: [DynamicText { id: 1 }] }, Element { tag: "p", namespace: None, attrs: [], children: [Text { text: "Another static text with more datas" }] }] }] }], node_paths: [[0, 0, 0, 0], [0, 0, 1, 0]], attr_paths: [] } }, dynamic_nodes: [Text(VText { value: "Test Recipe" }), Text(VText { value: "This is a test recipe" })], dynamic_attrs: [] }, mount: Cell { value: MountId(4) } } mount=MountId(4)
[INFO] dioxus_fullstack::render - Suspense resolved
get_recipe: done
[INFO] dioxus_core::diff::node - creating template self=VNode { vnode: VNodeInner { key: None, template: Cell { value: Template { name: "src/components/recipe.rs:19:13:2484", roots: [Element { tag: "div", namespace: None, attrs: [Static { name: "class", value: "flex flex-col justify-center overflow-hidden py-6", namespace: None }], children: [Element { tag: "div", namespace: None, attrs: [Static { name: "class", value: "mx-auto max-w-2xl", namespace: None }], children: [Element { tag: "h1", namespace: None, attrs: [Static { name: "class", value: "text-5xl text-center font-extrabold py-3", namespace: None }], children: [DynamicText { id: 0 }] }, Element { tag: "p", namespace: None, attrs: [Static { name: "class", value: "text-xl py-3", namespace: None }], children: [DynamicText { id: 1 }] }, Element { tag: "p", namespace: None, attrs: [], children: [Text { text: "Another static text with more datas" }] }] }] }], node_paths: [[0, 0, 0, 0], [0, 0, 1, 0]], attr_paths: [] } }, dynamic_nodes: [Text(VText { value: "Test Recipe" }), Text(VText { value: "This is a test recipe" })], dynamic_attrs: [] }, mount: Cell { value: MountId(4) } } mount=MountId(4)
[INFO] dioxus_fullstack::render - Suspense resolved
get_recipe: done
[INFO] dioxus_core::diff::node - creating template self=VNode { vnode: VNodeInner { key: None, template: Cell { value: Template { name: "src/components/recipe.rs:19:13:2484", roots: [Element { tag: "div", namespace: None, attrs: [Static { name: "class", value: "flex flex-col justify-center overflow-hidden py-6", namespace: None }], children: [Element { tag: "div", namespace: None, attrs: [Static { name: "class", value: "mx-auto max-w-2xl", namespace: None }], children: [Element { tag: "h1", namespace: None, attrs: [Static { name: "class", value: "text-5xl text-center font-extrabold py-3", namespace: None }], children: [DynamicText { id: 0 }] }, Element { tag: "p", namespace: None, attrs: [Static { name: "class", value: "text-xl py-3", namespace: None }], children: [DynamicText { id: 1 }] }, Element { tag: "p", namespace: None, attrs: [], children: [Text { text: "Another static text with more datas" }] }] }] }], node_paths: [[0, 0, 0, 0], [0, 0, 1, 0]], attr_paths: [] } }, dynamic_nodes: [Text(VText { value: "Test Recipe" }), Text(VText { value: "This is a test recipe" })], dynamic_attrs: [] }, mount: Cell { value: MountId(4) } } mount=MountId(4)
[INFO] dioxus_fullstack::render - Suspense resolved
get_recipe: done
[INFO] dioxus_core::diff::node - creating template self=VNode { vnode: VNodeInner { key: None, template: Cell { value: Template { name: "src/components/recipe.rs:19:13:2484", roots: [Element { tag: "div", namespace: None, attrs: [Static { name: "class", value: "flex flex-col justify-center overflow-hidden py-6", namespace: None }], children: [Element { tag: "div", namespace: None, attrs: [Static { name: "class", value: "mx-auto max-w-2xl", namespace: None }], children: [Element { tag: "h1", namespace: None, attrs: [Static { name: "class", value: "text-5xl text-center font-extrabold py-3", namespace: None }], children: [DynamicText { id: 0 }] }, Element { tag: "p", namespace: None, attrs: [Static { name: "class", value: "text-xl py-3", namespace: None }], children: [DynamicText { id: 1 }] }, Element { tag: "p", namespace: None, attrs: [], children: [Text { text: "Another static text with more datas" }] }] }] }], node_paths: [[0, 0, 0, 0], [0, 0, 1, 0]], attr_paths: [] } }, dynamic_nodes: [Text(VText { value: "Test Recipe" }), Text(VText { value: "This is a test recipe" })], dynamic_attrs: [] }, mount: Cell { value: MountId(4) } } mount=MountId(4)
[INFO] dioxus_fullstack::render - Suspense resolved
So the code after the sleep.await
gets called five times, seems like once a second when observing.
#[server]
pub async fn get_recipe(id: String) -> Result<Recipe, ServerFnError> {
println!("get_recipe: {}", id);
use tokio::time::{sleep, Duration};
sleep(Duration::from_millis(5000)).await;
println!("get_recipe: done");
Ok(Recipe {
id,
name: "Test Recipe".to_string(),
description: "This is a test recipe".to_string(),
ingredients: vec![],
steps: vec![],
})
}
from dioxus.
BTW didn't see those repeating get_recipe: done
with the CLI version (9ae3d14) but still the same hot reloading behavior.
from dioxus.
Actually it seems like those two cases don't ever get to produce a template. When I force a long delay on the server call, I can see in the browser inspector that the component contents for
None
case is never inserted into the DOM. It just has some<pre hidden>\</pre\>
placeholder there.
The reason for this was the use_server_future
. With use_resource
it works as expected. Although IMO the behavior should not be like that with the server future when dynamically switching components, instead of doing a full SSR of the page on initial load.
from dioxus.
Another weird thing I'm seeing in the logs is the execution of part of the server function multiple times.
[INFO] dioxus_fullstack::render - Suspense resolved get_recipe: done [INFO] dioxus_core::diff::node - creating template self=VNode { vnode: VNodeInner { key: None, template: Cell { value: Template { name: "src/components/recipe.rs:19:13:2484", roots: [Element { tag: "div", namespace: None, attrs: [Static { name: "class", value: "flex flex-col justify-center overflow-hidden py-6", namespace: None }], children: [Element { tag: "div", namespace: None, attrs: [Static { name: "class", value: "mx-auto max-w-2xl", namespace: None }], children: [Element { tag: "h1", namespace: None, attrs: [Static { name: "class", value: "text-5xl text-center font-extrabold py-3", namespace: None }], children: [DynamicText { id: 0 }] }, Element { tag: "p", namespace: None, attrs: [Static { name: "class", value: "text-xl py-3", namespace: None }], children: [DynamicText { id: 1 }] }, Element { tag: "p", namespace: None, attrs: [], children: [Text { text: "Another static text with more datas" }] }] }] }], node_paths: [[0, 0, 0, 0], [0, 0, 1, 0]], attr_paths: [] } }, dynamic_nodes: [Text(VText { value: "Test Recipe" }), Text(VText { value: "This is a test recipe" })], dynamic_attrs: [] }, mount: Cell { value: MountId(4) } } mount=MountId(4) [INFO] dioxus_fullstack::render - Suspense resolved spinning up hot reloading hot reloading ready 🔥 Hot Reload WebSocket connected Connected to hot reloading 🚀 🔮 Finding updates since last compile... finished get_recipe: done [INFO] dioxus_core::diff::node - creating template self=VNode { vnode: VNodeInner { key: None, template: Cell { value: Template { name: "src/components/recipe.rs:19:13:2484", roots: [Element { tag: "div", namespace: None, attrs: [Static { name: "class", value: "flex flex-col justify-center overflow-hidden py-6", namespace: None }], children: [Element { tag: "div", namespace: None, attrs: [Static { name: "class", value: "mx-auto max-w-2xl", namespace: None }], children: [Element { tag: "h1", namespace: None, attrs: [Static { name: "class", value: "text-5xl text-center font-extrabold py-3", namespace: None }], children: [DynamicText { id: 0 }] }, Element { tag: "p", namespace: None, attrs: [Static { name: "class", value: "text-xl py-3", namespace: None }], children: [DynamicText { id: 1 }] }, Element { tag: "p", namespace: None, attrs: [], children: [Text { text: "Another static text with more datas" }] }] }] }], node_paths: [[0, 0, 0, 0], [0, 0, 1, 0]], attr_paths: [] } }, dynamic_nodes: [Text(VText { value: "Test Recipe" }), Text(VText { value: "This is a test recipe" })], dynamic_attrs: [] }, mount: Cell { value: MountId(4) } } mount=MountId(4) [INFO] dioxus_fullstack::render - Suspense resolved get_recipe: done [INFO] dioxus_core::diff::node - creating template self=VNode { vnode: VNodeInner { key: None, template: Cell { value: Template { name: "src/components/recipe.rs:19:13:2484", roots: [Element { tag: "div", namespace: None, attrs: [Static { name: "class", value: "flex flex-col justify-center overflow-hidden py-6", namespace: None }], children: [Element { tag: "div", namespace: None, attrs: [Static { name: "class", value: "mx-auto max-w-2xl", namespace: None }], children: [Element { tag: "h1", namespace: None, attrs: [Static { name: "class", value: "text-5xl text-center font-extrabold py-3", namespace: None }], children: [DynamicText { id: 0 }] }, Element { tag: "p", namespace: None, attrs: [Static { name: "class", value: "text-xl py-3", namespace: None }], children: [DynamicText { id: 1 }] }, Element { tag: "p", namespace: None, attrs: [], children: [Text { text: "Another static text with more datas" }] }] }] }], node_paths: [[0, 0, 0, 0], [0, 0, 1, 0]], attr_paths: [] } }, dynamic_nodes: [Text(VText { value: "Test Recipe" }), Text(VText { value: "This is a test recipe" })], dynamic_attrs: [] }, mount: Cell { value: MountId(4) } } mount=MountId(4) [INFO] dioxus_fullstack::render - Suspense resolved get_recipe: done [INFO] dioxus_core::diff::node - creating template self=VNode { vnode: VNodeInner { key: None, template: Cell { value: Template { name: "src/components/recipe.rs:19:13:2484", roots: [Element { tag: "div", namespace: None, attrs: [Static { name: "class", value: "flex flex-col justify-center overflow-hidden py-6", namespace: None }], children: [Element { tag: "div", namespace: None, attrs: [Static { name: "class", value: "mx-auto max-w-2xl", namespace: None }], children: [Element { tag: "h1", namespace: None, attrs: [Static { name: "class", value: "text-5xl text-center font-extrabold py-3", namespace: None }], children: [DynamicText { id: 0 }] }, Element { tag: "p", namespace: None, attrs: [Static { name: "class", value: "text-xl py-3", namespace: None }], children: [DynamicText { id: 1 }] }, Element { tag: "p", namespace: None, attrs: [], children: [Text { text: "Another static text with more datas" }] }] }] }], node_paths: [[0, 0, 0, 0], [0, 0, 1, 0]], attr_paths: [] } }, dynamic_nodes: [Text(VText { value: "Test Recipe" }), Text(VText { value: "This is a test recipe" })], dynamic_attrs: [] }, mount: Cell { value: MountId(4) } } mount=MountId(4) [INFO] dioxus_fullstack::render - Suspense resolved get_recipe: done [INFO] dioxus_core::diff::node - creating template self=VNode { vnode: VNodeInner { key: None, template: Cell { value: Template { name: "src/components/recipe.rs:19:13:2484", roots: [Element { tag: "div", namespace: None, attrs: [Static { name: "class", value: "flex flex-col justify-center overflow-hidden py-6", namespace: None }], children: [Element { tag: "div", namespace: None, attrs: [Static { name: "class", value: "mx-auto max-w-2xl", namespace: None }], children: [Element { tag: "h1", namespace: None, attrs: [Static { name: "class", value: "text-5xl text-center font-extrabold py-3", namespace: None }], children: [DynamicText { id: 0 }] }, Element { tag: "p", namespace: None, attrs: [Static { name: "class", value: "text-xl py-3", namespace: None }], children: [DynamicText { id: 1 }] }, Element { tag: "p", namespace: None, attrs: [], children: [Text { text: "Another static text with more datas" }] }] }] }], node_paths: [[0, 0, 0, 0], [0, 0, 1, 0]], attr_paths: [] } }, dynamic_nodes: [Text(VText { value: "Test Recipe" }), Text(VText { value: "This is a test recipe" })], dynamic_attrs: [] }, mount: Cell { value: MountId(4) } } mount=MountId(4) [INFO] dioxus_fullstack::render - Suspense resolved
So the code after the
sleep.await
gets called five times, seems like once a second when observing.#[server] pub async fn get_recipe(id: String) -> Result<Recipe, ServerFnError> { println!("get_recipe: {}", id); use tokio::time::{sleep, Duration}; sleep(Duration::from_millis(5000)).await; println!("get_recipe: done"); Ok(Recipe { id, name: "Test Recipe".to_string(), description: "This is a test recipe".to_string(), ingredients: vec![], steps: vec![], }) }
Those logs will happen whenever a client makes a request to your server and the server renders the page. If you reload your page 5 times, you should see 5 logs. You may also more logs if an asset is trying to load that doesn't exist and you are rendering a page on a 404 route
from dioxus.
But I see in the logs only the get_recipe: done
message, not the first get_recipe: 1
message, which only occurs once. Couldn't really get this to happen again, so might have been some fluke as well, or some nasty timing issue.
from dioxus.
I think this is a race condition on how we register templates. Templates are given a template ID but that ID assignment can vary depending on the order in which we process them. If the template doesn't exist on the client when we handle its edits, we have nothing to direct those edits to. Hence why you only see edits for the actually loaded block of rsx.
This needs to be solved with more resilient handling of edits queued for nonexistent templates.
from dioxus.
Related Issues (20)
- Dioxus-desktop: add a method to enable the webview remote-debugging (for easier playwright compatibility)
- Page is reloading unnecessarily HOT 5
- Error compiling desktop project on linux (`linking with 'cc' failed`) HOT 3
- Replacing Text with Node Fails HOT 1
- Tailwind CSS example: including stylesheets using the mg! not work.
- Inline rsx within match never reevaluated when on of the arm's returns an empty rsx. HOT 2
- Error when calling "cargo clippy --workspace --examples --tests -- -D warnings"
- Clean up our core-macro implementation.
- Tokio version appears to be mising new_multi_thread fresh install with LiveView 0.5.0-alpha.0 HOT 1
- Hotreload poll causes server_futures to repeatedly get called HOT 1
- Move over to typed-builder instead of using its source directly
- Weird error with new signals lifetimes
- Move away from global event converter
- Move eval infrastructure into the base interpreter
- The event mounted interface is clunky - we should swap to a NodeRef approach
- Elements should be easier to extend
- Collapse events to `Event<dyn Data>`
- Form values should return a Vec of values HOT 4
- Hot reload disconnect loops when SSR takes more than 1sec HOT 1
- High CPU Load and Freeze HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from dioxus.