Dioxus 0.5中spawn函数未执行异步代码的问题排查
问题
使用Dioxus 0.5开发桌面应用时,组件中的spawn函数无法执行内部异步代码。代码编译正常无报错,点击按钮后无预期效果,但use_future或从事件处理器返回Future等其他异步方法可正常工作,且符合Dioxus文档的使用场景。
提交表单时能看到Creating user和父组件onsubmit回调中的Refreshing publishers,但看不到Inside spawn,用户也未创建(service方法正确,之前用use_future可正常工作)。
失效组件代码
use crate::logic::models::{Gender, Publisher}; use crate::logic::publishers_service; use crate::AppState; use dioxus::prelude::*; #[component] pub fn AddPublisherForm(onsubmit: EventHandler<()>) -> Element { let onsubmit = move |evt: Event<FormData>| { let vals = evt.data.values(); let name = vals.get("name"); let gender_string = vals.get("gender").unwrap().as_value(); let gender = match gender_string.as_str() { "m" => Gender::Male, "f" => Gender::Female, _ => Gender::Male, }; let suspended = vals.get("suspended").is_some(); if name.is_none() { return (); } let name = name.unwrap().as_value(); let state = use_context::<Signal<AppState>>(); println!("Creating user"); spawn(async move { println!("Inside spawn"); publishers_service::create( Publisher { id: None, name: name.clone(), gender, suspended, }, &state(), ) .await; }); onsubmit.call(()); }; rsx! { div { form { onsubmit: onsubmit, fieldset { legend { "Add publiser" }, input { name: "name" }, "male", input { r#type: "radio", name: "gender", value: "m", checked: true }, "female", input { r#type: "radio", name: "gender", value: "f", checked: false } "suspended", input { r#type: "checkbox", name: "suspended", checked: false } button { "create" } } } } } }
相关初始化代码
main.rs 数据库连接准备
#[derive(Clone)] pub struct AppState { connection: Pool<Sqlite>, } fn main() -> Result<()> { let rt = Runtime::new().unwrap(); let handle = rt.handle(); let db = handle.block_on(async { create_db().await }); let state = AppState { connection: db }; launch_app(state); Ok(()) }
应用启动代码
pub fn launch_app(state: AppState) { // Init logger dioxus_logger::init(Level::INFO).expect("failed to init logger"); LaunchBuilder::desktop() .with_cfg( Config::default() .with_custom_head("<link href=\"./base.css\" rel=\"stylesheet\">".to_string()) .with_menu(None), ) .with_context(state) .launch(App); }
分析与解决
核心原因:自定义Runtime与Dioxus的Runtime冲突
你在main函数中手动创建了tokio::Runtime,但Dioxus桌面应用会自动初始化自己的Runtime环境。手动创建的Runtime并未被Dioxus的spawn函数使用,导致你通过spawn提交的异步任务没有合适的执行上下文,无法启动。
另外,use_future能正常工作是因为它绑定到了Dioxus自身的Runtime上,而你手动创建的Runtime只在初始化数据库时被使用,和后续组件的异步任务无关。
解决步骤
1. 移除手动创建的Runtime
不需要在main中手动初始化tokio Runtime,Dioxus会自动处理。修改main函数如下:
fn main() -> Result<()> { let db = dioxus::tokio::block_on(async { create_db().await }); let state = AppState { connection: db }; launch_app(state); Ok(()) }
2. 拦截表单默认行为(可选但推荐)
当前代码未阻止表单的默认提交行为,可能导致不必要的重渲染干扰。建议在事件处理器开头添加:
evt.prevent_default();
3. 验证spawn行为
移除自定义Runtime后,Dioxus会自动将spawn的任务调度到正确的执行上下文,此时Inside spawn日志和数据库创建操作就能正常执行。
内容的提问来源于stack exchange,提问作者Drago96
相关产品推荐
相关产品推荐

