How to Upgrade to Dioxus 0.6
This guide will outline the API changes between the 0.5 and 0.6 releases. The 0.6 release contains breaking changes to:
- The
Elementtype - Prevent default
- Assets with Manganis
dioxus_loggerintegration withdioxus- The
launchfunction - The
evalfunction - The
dioxus-fullstackcrate - The router crate
- The
derive(Props)macro - The
dioxus-corecrate - Custom renderer API
- Global state management
Element
The element type has changed from Option<VNode> to Result<VNode, RenderError>. This makes it possible to bubble up errors while rendering with the ? operator, but it does remove the ability to return None from a component. Instead of returning None, you can return VNode::empty() or an empty rsx! macro.
Dioxus 0.5:
use dioxus::prelude::*; fn app() -> Element { let number = use_signal(|| -1); if number() < 0 { // ❌ In dioxus 0.6, the element type is a result, so None values cannot be returned directly return None; } rsx! { "Positive number: {number}" } }
Dioxus 0.6:
use dioxus::prelude::*; fn app() -> Element { let number = use_signal(|| -1); if number() < 0 { // ✅ You can return VNode::empty() instead return VNode::empty(); } if number() < 0 { // ✅ Or an empty rsx! macro return rsx! {}; } rsx! { "Positive number: {number}" } }
Prevent Default
Dioxus 0.1-0.5 used the prevent_default attribute to prevent default behavior of event handlers for every event. Dioxus 0.6 introduces more fine-grained control over preventing default behavior with the prevent_default function on the event type. Instead of setting the prevent_default attribute for all events you want to prevent, you can create event handlers that call event.prevent_default().
Dioxus 0.5:
use dioxus::prelude::*; fn app() -> Element { rsx! { a { href: "https://dioxuslabs.com", // ❌ The prevent default attribute is deprecated in dioxus 0.6 prevent_default: "onclick", "Don't navigate to dioxuslabs.com" } } }
Dioxus 0.6:
use dioxus::prelude::*; fn app() -> Element { rsx! { a { href: "https://dioxuslabs.com", // ✅ Instead, you can call event.prevent_default() inside the event handler onclick: move |event| event.prevent_default(), "Don't navigate to dioxuslabs.com" } } }
Note: Since event handlers run on the server in Liveview, events cannot be prevented quickly inside the event handler. Because of this, the new
prevent_defaultmethod does not prevent default behavior in Liveview.Instead you can use javascript inside the
onclickhandler to prevent default behavior.src/migration.rsuse dioxus::prelude::*; fn app() -> Element { rsx! { a { href: "https://dioxuslabs.com", // ✅ In liveview, you can use javascript to prevent default behavior "onclick": "event.preventDefault()", "Don't navigate to dioxuslabs.com" } } }
Assets
The syntax of the asset! macro has changed in Dioxus 0.6. Instead of accepting a single argument with both the path and the configuration for the asset, you can now pass in the path as the first argument and the configuration as a optional second argument.
The path the asset! macro accepts has also changed. Previously, the macro used to accept absolute and relative paths where relative paths were relative to the current crate directory. Now the macro only accepts absolute paths which are resolved relative to the root of the crate.
Dioxus 0.5:
use dioxus::prelude::*; fn app() -> Element { rsx! { img { src: asset!(image("./assets/static/bundle.png").size(100, 100)) } } }
Dioxus 0.6:
use dioxus::prelude::*; fn app() -> Element { rsx! { img { src: asset!("/assets/static/bundle.png", ImageAssetOptions::new().with_size(ImageSize::Manual { width: 100, height: 100 })) } } }
Logging
Dioxus 0.6 brings the dioxus-logger crate directly into dioxus itself.
Previously, you needed to add dioxus-logger to your Cargo.toml and then call its init function:
// cargo.toml: // dioxus-logger = "0.5" use dioxus::prelude::*; use tracing::Level; fn main() { // Init logger dioxus_logger::init(Level::INFO).expect("failed to init logger"); // Dioxus launch code dioxus::launch(app) }
Now, in Dioxus 0.6, the logger is implicit with launch. Simply call launch and the logger is initialized to a default log level. In development mode, the Debug tracing level is set, and in release only the Info level is set.
use dioxus::prelude::*; fn main() { dioxus::launch(app); }
If you still need to set the level manually or configure a custom subscriber, do that before launch. We expose the initialize_default function in case you need additional logging before your launch call:
use dioxus::prelude::*; fn main() { dioxus::logger::initialize_default(); tracing::info!("Logs received!"); dioxus::launch(app); }
Launch
The launch function was removed from the prelude. You must now import the launch method from dioxus or use it by its full path:
use dioxus::prelude::*; fn main() { // ❌ launch(app); dioxus::launch(app); // ✅ }
See https://github.com/DioxusLabs/dioxus/pull/2967 for more details.
Eval
evalwas moved from the prelude to thedocumentmodule. You must now call it withdocument::evalinstead ofeval:
use dioxus::prelude::*; fn app() -> Element { // ❌ use_effect(|| eval("console.log(1)")); use_effect(|| document::eval("console.log(1)")); // ✅ rsx! {} }
- The
evalfeature flag was removed from thedioxus-htmlcrate and the functionality ofEvalProviderwas moved to the newdioxus-documentcrate. Custom renderers must now provide aRc<dyn Document>context to the application to makeevaland head elements work correctly. See https://github.com/DioxusLabs/dioxus/pull/2635 for more details. Eval::recvandEval::joinnow returns any value that implementsDeserializeOwnedinstead ofserde_json::Value.Eval::sendnow accepts any value that implementsSerialize. See https://github.com/DioxusLabs/dioxus/pull/3035 for more details
Fullstack
- The feature
dioxus/axumwas renamed todioxus/server
[features] default = [] # ❌ server = ["dioxus/axum"] server = ["dioxus/server"] # ✅ web = ["dioxus/web"]
See https://github.com/DioxusLabs/dioxus/pull/3186 for more details
- The
fullstack::Configitem was removed. You can now pass the platform configs into theLaunchBuilderdirectly. For example, if you want to set the rootname on each platform, you can set the root name in each config:
LaunchBuilder::new() // Only set the server config if the server feature is enabled .with_cfg(server_only! { ServeConfigBuilder::default().root_id("app") }) // You also need to set the root id in your web config .with_cfg(web! { dioxus::web::Config::default().rootname("app") }) // And desktop config .with_cfg(desktop! { dioxus::desktop::Config::default().with_root_name("app") }) .launch(app);
See https://github.com/DioxusLabs/dioxus/pull/2967 for more details.
- The dioxus-cli now proxies fullstack applications at a port behind a reverse proxy. If you have a custom axum server, you must serve your application at the port returned by
dioxus_cli_config::server_portand the address returned bydioxus_cli_config::server_ipor the complete address returned bydioxus_cli_config::fullstack_address_or_localhostduring development:
#[cfg(feature = "server")] #[tokio::main] async fn main() { // Get the address the server should run on. If the CLI is running, the CLI proxies fullstack into the main address // and we use the generated address the CLI gives us let address = dioxus_cli_config::fullstack_address_or_localhost(); // Launch the fullstack application on the address the CLI is proxying let router = axum::Router::new() .serve_dioxus_application(ServeConfigBuilder::default(), App); let router = router.into_make_service(); let listener = tokio::net::TcpListener::bind(address).await.unwrap(); axum::serve(listener, router).await.unwrap(); }
See https://github.com/DioxusLabs/dioxus/pull/2258 for more details.
serve_dioxus_applicationwas changed to accept a component directly instead of a virtual dom factory. See https://github.com/DioxusLabs/dioxus/pull/2515 for more details.register_server_fnswas renamed toregister_server_functions. See https://github.com/DioxusLabs/dioxus/pull/2515 for more details.RenderHandleState::newaccepts a newServeConfigargument. See https://github.com/DioxusLabs/dioxus/pull/2862 for more details.ServeConfigBuilder::buildreturns a result. It may fail during desktop builds if noindex.htmlfile is found. This error is fine to ignore in desktop builds. You can pass the builder directly toserve_dioxus_applicationto only serve the index.html file if it exists. See https://github.com/DioxusLabs/dioxus/pull/2862 for more details.dioxus_fullstack::Config::addrwas removed. You can now export thePORTandIPenvironment variables to set the address thelaunchmethod uses for the server.
Router
- The
Routablederive macro no longer accepts fields that are not present in theroute("/route")if the web feature is enabled. See https://github.com/DioxusLabs/dioxus/pull/2159 for more details. - The
ToRouteSegmentstrait in the router was changed from acceptingselfto accepting&self. This means you can now implement it forTdirectly instead of&T. See https://github.com/DioxusLabs/dioxus/pull/2283 for more details.
derive(Props)
#[props(into)]is ignore on any String props. String props already acceptimpl ToStringwhich is implemented for many of the same types, but if you implementInto<String>for a specific type, your code may require some changes. See https://github.com/DioxusLabs/dioxus/pull/2501 for more details- Properties that start with an uppercase letter are no longer accepted. This allows us to autocomplete Components. See https://github.com/DioxusLabs/dioxus/pull/2652 for more details.
State Management
use_coroutinenow acceptsimpl FnMutinstead ofimpl FnOnce. This was required to support restarting the coroutine without rerunning the component. See https://github.com/DioxusLabs/dioxus/pull/3005 for more details.Signal::global_memonow requiresT: PartialEqjust likeuse_memo. See https://github.com/DioxusLabs/dioxus/pull/2851 for more details.GlobalMemo<T>is now a trait alias forGlobal<Memo<T>, T>andGlobalSignal<T>is now a trait alias forGlobal<Signal<T>, T>. To get the underlyingMemoorSignal, you can now use theresolvemethod instead ofsignalormemo. See https://github.com/DioxusLabs/dioxus/pull/2851 for more details.- The
Readabletrait in dioxus signals now requires atry_peek_uncheckedmethod instead ofpeek_unchecked. See https://github.com/DioxusLabs/dioxus/pull/2714 for more details. - The
check_generationfeature flag was removed from thegenerational-boxcrate. See https://github.com/DioxusLabs/dioxus/pull/2638 for more details.
Core changes
- The
Template::namefield was removed. See https://github.com/DioxusLabs/dioxus/pull/2799 for more details. Properties::into_vcomponentnow accepts only therender_fninstead of therender_fnandcomponent_name. This change fixes the name of re-exported components. Fixes https://github.com/DioxusLabs/dioxus/pull/2744- The field
VNode::templateis nowTemplateinstead ofCell<Template>. See https://github.com/DioxusLabs/dioxus/pull/2705 for more details Mutations::santizewas renamed toMutations::sanitize. See https://github.com/DioxusLabs/dioxus/pull/2653 for more details.- The variant
AttributeValue::Anynow containsRc<dyn AnyValue>instead ofBox<dyn AnyValue>to makeAttributeValueClone. See https://github.com/DioxusLabs/dioxus/pull/2705 for more details
Custom Renderers
If you are building a custom renderer, there were some breaking changes to hot reloading and rsx that you should be aware of:
- The CLI hot reloading format changed significantly. Custom renderers must switch from
dioxus-hot-reloadtodioxus_devtools. Renderers can connect to the hot reloading engine with the [ connect ] (https://docs.rs/dioxus-devtools/0.6.0/dioxus_devtools/fn.connect.html) function. See https://github.com/DioxusLabs/dioxus/pull/2258 for more details. - The format of custom elements was changed to improve autocomplete. The
dioxus_elementsnamespace must now contain each element as a module with a TAG_NAME and NAME_SPACE constant inside that module. Each attribute should be another constant in that module. The top-leveldioxus_elementsmodule should contain acompletionsmodule with aCompleteWithBracesenum that re-exports each element the namespace supports for braces autocomplete. See https://github.com/DioxusLabs/dioxus/pull/2421 for more details. - The format for custom event handlers changed include
eventname::call_with_explicit_closureto provide better type inference for inline closures. See https://github.com/DioxusLabs/dioxus/pull/2437 for more details
If you are also using dioxus-html, there are a few more breaking changes:
- A
file_sizemethod was added to theFileEnginetrait. Any custom renderers must implement this method. See https://github.com/DioxusLabs/dioxus/pull/2323/files for more details. HtmlEventConverterhas a newconvert_resize_datamethod which must be implemented by any custom renderers that use dioxus-html. See https://github.com/DioxusLabs/dioxus/pull/2479 for more details- The web and native features were removed from the
dioxus-htmlcrate. See https://github.com/DioxusLabs/dioxus/pull/3006 for more details. dioxus_html::AttributeDiscriptionwas renamed todioxus_html::AttributeDescription. See https://github.com/DioxusLabs/dioxus/pull/2653 for more details.
Minor Breaking Changes
There were several more minor breaking changes in Dioxus 0.6:
- Many implicit features from dioxus crates were removed. These features were automatically generated by cargo and generally not functional. See https://github.com/DioxusLabs/dioxus/pull/2512 for more details.
dioxus_autofmt::write_block_outaccepts&CallBodyinstead ofCallBody. See https://github.com/DioxusLabs/dioxus/pull/2573 for more details.- The
panic_hookfeature which provides a console panic message for wasm panics was moved from thedioxus-webcrate to thedioxus-loggercrate. The handler is still provided by default. See https://github.com/DioxusLabs/dioxus/pull/3302 for more details.