Fullstack GUI library for web, desktop, mobile, and more.
APACHE-2.0 License
Bot releases are hidden (Show)
Dioxus 0.6 includes improvements to several areas of dioxus. The highlights are:
We introduced our new asset system, Manganis, in an alpha state with the 0.5 release. Dioxus 0.6 stabilizes the asset system and fixes several bugs and performance issues. You can try out the new linker based asset system by including an asset!
anywhere in your code. It will automatically be optimized and bundled across all platforms:
rsx! {
img { src: asset!("./assets/myimg.png") }
}
In addition to the Manganis asset system, dioxus 0.6 includes a new way to include assets into your html. The new Script
, Link
, Style
, and Meta
components let you link to assets anywhere in your html. These components will automatically be hoisted into the <head>
across all platforms and deduplicated by the source:
#[component]
fn MyStyledComponent() -> {
rsx! {
head::Link {
rel: "stylesheet",
href: asset!("./assets/style.css")
}
"This component is styled"
}
}
RSX now supports autocomplete everywhere. In addition to expressions, elements, components and attributes now autocomplete correctly:
https://github.com/user-attachments/assets/10781eef-de07-491d-aaa3-f75949b32190
The new version of RSX also features better error messages for incorrect markup:
In 0.6, RSX hot reloading is much more consistent. You can move around and duplicate expressions anywhere in an rsx block or create new literals anywhere in an rsx block. This means you can now create new formatted text nodes, new formatted attributes or tweak properties on the fly without recompiling!
https://github.com/user-attachments/assets/15bd7d6d-24ae-4cc9-abde-e063879cd842
Async is a core component of any UI framework. Dioxus provides hooks to handle async state. You can start a future and handle the loading and resolved states within the component:
#[component]
fn Article() -> Element {
// Use resource starts a future in the background and returns the current state
let article = use_resource(fetch_article);
rsx! {
// You can match the state of the future to render either a loading state or the resolved state
match article() {
Some(article) => rsx! { "{article}" },
None => rsx! { p { "Loading..." } }
}
}
}
This works ok if you have a single future, but it quickly gets messy when combining many futures into one UI:
#[component]
fn Article() -> Element {
// Use resource starts a future in the background and returns the current state
let Some(title) = use_resource(fetch_title).cloned() else {
return rsx! { "loading..." }
};
let Some(article) = use_resource(fetch_article).cloned() else {
return rsx! { "loading..." }
};
let Some(category) = use_resource(move || article.title()).cloned() else {
return rsx! { "loading..." }
};
rsx! {
Title { "{title}" }
Body { category, article }
}
}
In addition to hooks, we need a way to display a different state when async is loading. Dioxus 0.6 introduces a new core primitive for async UI called suspense boundaries. A suspense boundary is a component that renders a placeholder when any child component is loading:
rsx! {
SuspenseBoundary {
fallback: |context: SuspenseContext| rsx! {
// Render a loading placeholder if any child component is suspended
"Loading..."
},
Article {}
}
}
In any child component, you can just bubble up the pending state with ?
to pause rendering until the future is finished:
#[component]
fn Article() -> Element {
let title = use_resource(fetch_title).suspend()?;
let article = use_resource(fetch_article).suspend()?;
let category = use_resource(move || article.title()).suspend()?;
// Since we bubbled up all the pending futures with `?` we can just
// handle the happy path in the component
rsx! {
Title { "{title}" }
Body { category, article }
}
}
Along with suspense boundaries, dioxus fullstack also supports streaming each suspense boundary in from the server. Instead of waiting for the whole page to load, dioxus fullstack streams in each chunk with the resolved futures as they finish:
https://github.com/user-attachments/assets/7aa94563-78b3-4f17-be1d-4cad77efd238
0.6 also introduces error boundaries which let you display an error message if any child component runs into an error:
#[component]
fn Root() -> Element {
rsx! {
ErrorBoundary {
handle_error: |errors: ErrorContext| {
match errors.show() {
// Render the view the child component through with the error
Some(view) => view,
// Or a fallback if the error doesn't come with a view
None => rsx! {
pre {
color: "red",
"oops, we ran into an error\n{errors:#?}"
}
}
}
},
Contents {}
}
}
}
You can throw an error from any child component while rendering or handling events:
#[component]
fn Double(input: String) -> Element {
// You can use ? to throw an event during rendering
let parsed: f32 = input.parse()?;
let doubled = parsed * 2.0;
rsx! {
"{doubled}"
}
}
#[component]
fn DoubleButton(mut count: Signal<u8>) -> Element {
rsx! {
button {
onclick: move |_| {
// Errors can have an associated view which the error boundary can
// choose to show
let doubled = count().checked_mul(2).show(|_|
rsx! { "multiplying {count} by 2 would overflow the u8" }
)?;
count.set(doubled);
Ok(())
},
"Double!"
}
}
}
The Dioxus CLI has been rewritten to support a TUI with build progress, and multiple views for logs. It has shortcuts for common actions, and displays progress in both the TUI and the site as the project loads:
https://github.com/user-attachments/assets/6136627b-3760-4e1e-aaca-2e7315558e32
Blitz has been rewritten to use Firefox's browser engine, Stylo. The new version of Blitz is much more capable with proper accessibility support, IME support, and better text support. Blitz should be a drop in replacement for dioxus desktop for the small subset of HTML it supports. Keep in mind Blitz is still experimental and not ready for production use. You can try Blitz by adding dioxus_blitz from the git repo:
cargo add dioxus-blitz --git https://github.com/DioxusLabs/blitz
Launching your Dioxus app with the blitz renderer:
dioxus_blitz::launch(app);
Dioxus 0.6 also includes a number of smaller ergonomic tweaks that should help dioxus feel a lot more consistent
Dioxus 0.6 splits out static generation into its own platform to make it easier to set up:
//! Static generation works out of the box with the router. Just add a router anywhere in your app and it will generate any static routes for you!
#![allow(unused)]
use dioxus::prelude::*;
// Generate all routes and output them to the static path
fn main() {
launch(|| {
rsx! {
Router::<Route> {}
}
});
}
#[derive(Clone, Routable, Debug, PartialEq)]
enum Route {
#[route("/")]
Home {},
#[route("/blog")]
Blog,
}
#[component]
fn Blog() -> Element {
rsx! {
Link { to: Route::Home {}, "Go to counter" }
table {
tbody {
for _ in 0..100 {
tr {
for _ in 0..100 {
td { "hello!" }
}
}
}
}
}
}
}
#[component]
fn Home() -> Element {
let mut count = use_signal(|| 0);
rsx! {
Link { to: Route::Blog {}, "Go to blog" }
div {
h1 { "High-Five counter: {count}" }
button { onclick: move |_| count += 1, "Up high!" }
button { onclick: move |_| count -= 1, "Down low!" }
}
}
}
Fullstack state now propagates from the launch builder into server functions which makes it much easier to set up state that is shared throughout your application like a database pool:
fn main() {
LaunchBuilder::new().with_context(1234567890u32).launch(app);
}
#[server]
async fn get_server_data() -> Result<String, ServerFnError> {
let FromContext(context): FromContext<u32> = extract().await?;
Ok(format!("the context was {context}"))
}
Dioxus 0.6 expands EventHandler
s into callbacks which let you both take and return arguments. Callbacks are a Copy
version of Box<dyn FnMut(Args) -> Ret>
built specifically for UI in Rust
#[component]
fn DoubleButton(double: Callback<u32, u32>) -> Element {
let mut count = use_signal(|| 1);
rsx! {
button {
// Callbacks let you easily inject custom logic into your components
onclick: move |_| count.set(double(count())),
"{count}"
}
}
}
Dioxus 0.6 also expands the warning system to include hints for several problematic behaviors. Dioxus now warns if components are called as functions, state is passed up the component tree, or a component rerun is triggered while rendering.
We also improved the inline documentation throughout the dioxus crates. Many common items now include in depth examples, explanations, and help for common errors. For comparison, here is the documentation in 0.5 and 0.6 for oninput:
and use_memo:
Dioxus 0.6 also includes a plethora of bug fixes and consistency tweaks. Over 200 issues closed with 100 bugs fixed
Testing the alpha release and opening issues for any bugs you run into is a great way to contribute back to dioxus!
Feel free to hop into the discord to give feedback and/or chat about the new changes.
tracing::warn!
instead of error!
when assets not being preloaded by @photino in https://github.com/DioxusLabs/dioxus/pull/2251
tracing::warn!
instead of error!
when the dioxus CLI is not used by @photino in https://github.com/DioxusLabs/dioxus/pull/2250
use_hook
docs by @marc2332 in https://github.com/DioxusLabs/dioxus/pull/2296
use_resource
docs by @marc2332 in https://github.com/DioxusLabs/dioxus/pull/2303
dx create
options to skip user interaction by @Andrew15-5 in https://github.com/DioxusLabs/dioxus/pull/1872
#[doc]
field attributes in Props
derive macro by @MrGVSV in https://github.com/DioxusLabs/dioxus/pull/2456
RwLock::try_read
with RwLock::read
in SyncStorage
by @ribelo in https://github.com/DioxusLabs/dioxus/pull/2463
#[props(into)]
on Strings by @ealmloff in https://github.com/DioxusLabs/dioxus/pull/2501
dioxus_desktop::Config
to also allow for asynchronous custom protocol handlers by @d3rpp in https://github.com/DioxusLabs/dioxus/pull/2535
README.md
About cli-dev
Profile by @DogeDark in https://github.com/DioxusLabs/dioxus/pull/2560
for/if/body
, formatted strings, literals, component props, nested rsx, light CLI rewrite, cli TUI by @jkelleyrtp in https://github.com/DioxusLabs/dioxus/pull/2258
impl Fn()
instead of a function pointer by @oskardotglobal in https://github.com/DioxusLabs/dioxus/pull/2583
expect
error messages by @matthunz in https://github.com/DioxusLabs/dioxus/pull/2629
debug_assertions
in core::tasks
by @matthunz in https://github.com/DioxusLabs/dioxus/pull/2703
always_on_top
CLI Setting by @DogeDark in https://github.com/DioxusLabs/dioxus/pull/2715
p
option for package
to match cargo
by @matthunz in https://github.com/DioxusLabs/dioxus/pull/2738
-package
to Cargo #1547 by @matthunz in https://github.com/DioxusLabs/dioxus/pull/2740
dx fmt
by @matthunz in https://github.com/DioxusLabs/dioxus/pull/2745
WebEventExt
by @matthunz in https://github.com/DioxusLabs/dioxus/pull/2707
Full Diff: https://github.com/DioxusLabs/dioxus/compare/v0.5.1...v0.6.0-alpha.1
Published by jkelleyrtp 7 months ago
Thanks everyone for the great feedback for the 0.5.0 launch! We're releasing 0.5.1 now with a bunch of bug fixes.
This includes some stuff like fixing async polling, some smalls issues with memos and resources, and a memory leak in EventHandler.
We strongly recommend you upgrade your dioxus project with cargo update
!
The autoformatter also changed a bit, so if you're using the VSCode extension, you should get the updates automatically.
create
command was renamed to new
by @foresterre in https://github.com/DioxusLabs/dioxus/pull/2174
use_on_destroy
docs by @marc2332 in https://github.com/DioxusLabs/dioxus/pull/2199
Full Changelog: https://github.com/DioxusLabs/dioxus/compare/v0.5.0...v0.5.1
Published by ealmloff 7 months ago
Here at Dioxus Labs, we have an unofficial rule: only one rewrite per year.
Our last rewrite brought some amazing features: templates, hotreloading, and insane performance. However, don’t be mistaken, rewrites are scary, time consuming, and a huge gamble. We started this new rewrite on January 1st of 2024, completed it by Feburary 1st, and then spent another month and a half writing tests, squashing bugs, and polishing documentation. Rewrites are absolutely not for the faint of heart.
If you’re new here, Dioxus (dye•ox•us) is a library for building GUIs in Rust. Originally, I built Dioxus as a rewrite of Yew with the intention of supporting proper server-side-rendering. Eventually, Dioxus got popular, we got some amazing sponsors, and I went full time. We’ve grown from a team of 1 (me) to a team of 4(!) - pulled entirely from the wonderful dioxus community.
Now, Dioxus is something a little different. Real life, actual companies are shipping web apps, desktop apps, and mobile apps with Dioxus. What was once just a fun little side project powers a small fraction of apps out in the wild. We now have lofty goals of simplifying the entire app development ecosystem. Web, Desktop, Mobile, all end-to-end typesafe, blazing fast, living under one codebase. The dream!
With 0.5 we took a hard look at how Dioxus would need to change to achieve those goals. The request we got from the community was clear: make it simpler, make it robust, make it polished.
This is probably the biggest release of Dioxus ever, with so many new features, bug fixes, and improvements that I can’t list them all. We churned over 100,000 lines of code (yes, 100,000+) with over 1,400 commits between 0.4.3 and 0.5.0. Here’s a quick overview:
dioxus-core
, removing all unsafe codeuse_state
and use_ref
for a clone-free Signal
-based APIcx: Scope
statelaunch
function that starts your app for any platformWebSys
event types<a/>
properties)To make Dioxus simpler, we wanted to remove lifetimes entirely. Newcomers to rust are easily scared off by lifetime issues, and even experienced Rustaceans find wading through obtuse error messages exhausting.
In dioxus 0.1-0.4, every value in a component lives for a 'bump
lifetime. This lifetime lets you easily use hooks, props and the scope within event listeners without cloning anything. It was the chief innovation that made Dioxus so much easier to use than Yew when it was released.
// Scope and Element have the lifetime 'bump
fn OldDioxusComponent(cx: Scope) -> Element {
// hook has the lifetime 'bump
let mut state = use_state(cx, || 0);
cx.render(rsx! {
button {
// The closure has the lifetime 'bump which means you don't
// need to clone hook before you move it into the closure
onclick: move |_event| *state += 1,
}
})
}
This works great for hooks most of the time. The lifetime lets you omit a bunch of manual clones every time you want to use a value inside an EventHandler (onclick, oninput, etc).
However, the lifetime doesn’t work for futures. Futures in dioxus need to be 'static
which means you always need to clone values before you use them in the future. Since a future might need to run while the component is rendering, it can’t share the component’s lifetime.
// Scope and Element have the lifetime 'bump
fn OldDioxusComponent(cx: Scope) -> Element {
// state has the lifetime 'bump
let state = use_state(cx, || 0);
cx.spawn({
// Because state has the lifetime 'bump, we need to clone it to make it
// 'static before we move it into the 'static future
let state = state.clone();
async move {
println!("{state}");
}
});
// ...
}
If you don’t clone the value, you will run into an error like this:
4 | fn OldDioxusComponent(cx: Scope) -> Element {
| --
| |
| `cx` is a reference that is only valid in the function body
| has type `&'1 Scoped<'1>`
...
8 | / cx.spawn(async move {
9 | | println!("{state}");
10 | | });
| | ^
| | |
| |______`cx` escapes the function body here
| argument requires that `'1` must outlive `'static`
The error complains that cx
must outlive 'static
without mentioning the hook at all which can be very confusing.
Dioxus 0.5 fixes this issue by first removing scopes and the 'bump
lifetime and then introducing a new Copy
state management solution called signals. Here is what the component looks like in dioxus 0.5:
// Element has no lifetime, and you don't need a Scope
fn NewComponent() -> Element {
// state is 'static and Copy, even if the inner value you store is not Copy
let mut state = use_signal(|| 0);
// State is already 'static and Copy, so it is copied into the future automatically
spawn(async move {
println!("{state}");
});
rsx! {
button {
// The closure has the lifetime 'static, but state is copy so you don't need to clone into the closure
onclick: move |_event| state += 1,
}
}
}
While this might seem like a rather innocuous change, it has an impressively huge impact on how easy it is to write new components. I’d say building a new Dioxus app is about 2-5x easier with this change alone.
In the new version of dioxus, scopes and the 'bump
lifetime have been removed! This makes declaring a component and using runtime functions within that component much easier:
You can now declare a component by just accepting your props directly instead of a scope parameter
#[component]
fn MyComponent(name: String) -> Element {
rsx! { "Hello {name}!" }
}
And inside that component, you can use runtime functions directly
spawn(async move {
tokio::time::sleep(Duration::from_millis(100)).await;
// You can even use runtime functions inside futures and event handlers!
let context: i32 = consume_context();
});
Now that lifetimes are gone, Element
s are 'static
which means you can use them in hooks or even provide them through the context API. This makes some APIs like virtual lists in dioxus significantly easier. We expect more interesting APIs to emerge from the community now that you don’t need to be a Rust wizard to implement things like virtualization and offscreen rendering.
Removing the 'bump
lifetime along with the scope gave us a chance to remove a lot of unsafe from dioxus. dioxus-core 0.5 contains no unsafe code 🎉
There’s still a tiny bit of unsafe floating around various dependencies that we plan to remove throughout the 0.5 release cycle, but way less: all quite simple to cut or unfortunately necessary due to FFI.
Dioxus 0.5 introduces Signals as the core state primitive for components. Signals have two key advantages over the existing use_state
and use_ref
hooks: They are always Copy
and they don’t require manual subscriptions.
Signal<T>
is Copy
, even if the inner T
values is not. This is enabled by our new generational-box crate (implemented with zero unsafe). Signals can even optionally be Send+Sync
if you need to move them between threads, removing the need for a whole class of specialized state management solutions.
The combination of Copy + Send + Sync
Signals, and static components makes it incredibly easy to move state to anywhere you need it:
fn Parent() -> Element {
// We use a sync signal here so that we can use it in other threads,
// but you could use a normal signal if you have !Send data
let mut state = use_signal_sync(|| 0);
spawn(async move {
// Signals have a ton of helper methods that make them easy to work with.
// You can call a signal like a function to get the current value
let value: i32 = state();
});
// Because signals can be sync, we can copy them into threads easily
std::thread::spawn(move || {
loop {
std::thread::sleep(Duration::from_millis(100));
println!("{state}");
}
});
render! {
button {
// You can easily move it into an event handler just like use_state
onclick: move |_| state += 1
}
}
}
With Copy
state, we’ve essentially bolted on a light form of garbage collection into Rust that uses component lifecycles as the triggers for dropping state. From a memory perspective, this is basically the same as 0.4, but with the added benefit of not needing to explicitly Clone
anything.
Signals are smarter about what components rerun when they are changed. A component will only rerun if you read the value of the signal in the component (not in an async task or event handler). In this example, only the child will re-render when the button is clicked because only the child component is reading the signal:
fn Parent() -> Element {
let mut state = use_signal(|| 0);
rsx! {
button { onclick: move |_| state += 1, "increment" }
Child { state }
}
}
#[component]
fn Child(state: Signal<i32>) -> Element {
rsx! { "{state}" }
}
Smarter subscriptions let us merge several different hooks into signals. For example, we were able to remove an entire crate dedicated to state management: Fermi. Fermi provided what was essentially a use_state
API where statics were used as keys. This meant you could declare some global state, and then read it in your components:
static COUNT: Atom<i32> = Atom::new(|| 0);
fn Demo(cx: Scope) -> Element {
let mut count = use_read_atom(cx, &COUNT);
rsx! { "{count}" }
}
Since fermi didn’t support smart subscriptions, you had to explicitly declare use the right use_read
/ use_write
hooks to subscribe to the value. In Dioxus 0.5, we just use signals, eliminating the need for any sort of external state management solution altogether.
// You can use a lazily initialized signal called
// GlobalSignal in static instead of special Fermi atoms
static COUNT: GlobalSignal<i32> = Signal::global(|| 0);
// Using the GlobalSignal is just the same as any other signal!
// No need for use_read or use_write
fn Demo() -> Element {
rsx! { "{COUNT}" }
}
Signals even work with the context API, so you can quickly share state between components in your app:
fn Parent() -> Element {
// Create a new signal and provide it to the context API
// without a special use_shared_state hook
let mut state = use_context_provider(|| Signal::new(0));
rsx! {
button { onclick: move |_| state += 1, "Increment" }
Child {}
}
}
fn Child() -> Element {
// Get the state from the context API
let state = use_context::<Signal<i32>>();
rsx! { "{state}" }
}
Smart subscriptions also apply to hooks. Hooks like use_future
and use_memo
will now automatically add signals you read inside the hook to the dependencies of the hook:
// You can use a lazily initialized signal called GlobalSignal in static instead of special Fermi atoms
static COUNT: GlobalSignal<i32> = Signal::global(|| 0);
fn App() -> Element {
// Because we read COUNT inside the memo, it is automatically added to the memo's dependencies
// If we change COUNT, then the memo knows it needs to rerun
let memo = use_memo(move || COUNT() / 2);
rsx! { "{memo}" }
}
Since it’s release, dioxus has used a synthetic event system to create a cross platform event API. Synthetic events can be incredibly useful to make events work across platforms and even serialize them across the network, but they do have some drawbacks.
Dioxus 0.5 finally exposes the underlying event type for each platform along with a trait with a cross platform API. This has two advantages:
fn Button() -> Element {
rsx! {
button {
onclick: move |event| {
let web_sys_event: web_sys::MouseEvent = event.web_event();
web_sys::console::log_1(&web_sys_event.related_target.into());
}
}
}
}
Again, this seems like a small change on the surface, but opens up dozens of new use cases and possible libraries you can build with dioxus.
Dioxus 0.5 introduces a new cross platform API to launch your app. This makes it easy to target multiple platforms with the same application. Instead of pulling in a separate renderer package, you can now enable a feature on the dioxus crate and call the launch function from the prelude:
[dependencies]
dioxus = "0.5"
[features]
default = []
desktop = ["dioxus/desktop"]
fullstack = ["dioxus/fullstack"]
server = ["dioxus/axum"]
web = ["dioxus/web"]
use dioxus::prelude::*;
fn main() {
dioxus::launch(|| rsx!{ "hello world" })
}
With that single application, you can easily target:
# Desktop
dx serve --platform desktop
# SPA web
dx serve --platform web
# Or a fullstack application
dx serve --platform fullstack
The CLI is now smart enough to automatically pass in the appropriate build features depending on the platform you’re targeting.
Currently assets in dioxus (and web applications in general) can be difficult to get right. Links to your asset can easily get out of date, the link to your asset can be different between desktop and web applications, and you need to manually add assets you want to use into your bundled application. In addition to all of that, assets can be a huge performance bottleneck.
Lets take a look at the dioxus mobile guide in the docsite as an example:
The 0.4 mobile guide takes 7 seconds to load and transfers 9 MB of resources. The page has 6 different large image files which slows down the page loading times significantly. We could switch to a more optimized image format like avif
, but manually converting every screenshot is tedious and time consuming.
Lets take a look at the 0.5 mobile guide with the new asset system:
The new mobile guide takes less than 1 second to load and requires only 1/3 of the resources with the exact same images!
Dioxus 0.5 introduces a new asset system called manganis. Manganis integrates with the CLI to check, bundle and optimize assets in your application. The API is currently unstable so the asset system is currently published as a separate crate. In the new asset system, you can just wrap your assets in the mg!
macro and they will automatically be picked up by the CLI. You can read more about the new asset system in the manganis docs.
As we continue to iterate on the 0.5 release, we plan to add hot reloading to manganis assets, so you can interactively add new the features to your app like CSS, images, tailwind classes, and more without forcing a complete reload.
As part of our asset system overhaul, we implemented hotreloading of CSS files in the asset directory. If a CSS file appears in your RSX, the dx
CLI will watch that file and immediately stream its updates to the running app. This works for web, desktop, and fullstack, with mobile support coming in a future mobile-centric update.
https://github.com/DioxusLabs/dioxus/assets/66571940/ece55e95-cf2b-4216-b04e-fe3c23d9ff78
What’s even niftier is that you can stream these changes to several devices at once, unlocking simultaneous hotreloading across all devices that you target:
https://github.com/DioxusLabs/dioxus/assets/66571940/315264fc-be68-4c47-b2fc-9a2233ccffc1
Dioxus implements several optimizations to make diffing rendering fast. Templates let dioxus skip diffing on any static parts of the rsx macro. However, diffing is only one side of the story. After you create a list of changes you need to make to the DOM, you need to apply them.
We developed sledgehammer for dioxus web to make applying those mutations as fast as possible. It makes manipulating the DOM from Rust almost as fast as native JavaScript.
In dioxus 0.5, we apply that same technique to apply changes across the network as fast as possible. Instead of using json to communicate changes to the desktop and liveview renderers, dioxus 0.5 uses a binary protocol.
For render intensive workloads, the new renderer takes only 1/5 the time to apply the changes in the browser with 1/2 the latency. Here is one of the benchmarks we developed while working on the new binary protocol. In dioxus 0.4, the renderer was constantly freezing. In dioxus 0.5, it runs smoothly:
Dioxus 0.4
https://github.com/DioxusLabs/dioxus/assets/66571940/d8c09989-ce99-4b80-b5a7-8ffaf53dbf87
Dioxus 0.5
https://github.com/DioxusLabs/dioxus/assets/66571940/2166880c-b7ce-414d-8f55-570b84a246f0
One common pattern when creating components is providing some additional functionality to a specific element. When you wrap an element, it is often useful to provide some control over what attributes are set in the final element. Instead of manually copying over each attribute from the element, dioxus 0.5 supports extending specific elements and spreading the attributes into an element:
#[derive(Props, PartialEq, Clone)]
struct Props {
// You can extend a specific element or global attributes
#[props(extends = img)]
attributes: Vec<Attribute>,
}
fn ImgPlus(props: Props) -> Element {
rsx! {
// You can spread those attributes into any element
img { ..props.attributes }
}
}
fn app() -> Element {
rsx! {
ImgPlus {
// You can use any attributes you would normally use on the img element
width: "10px",
height: "10px",
src: "https://example.com/image.png",
}
}
}
Another huge quality-of-life feature we added was the ability to use shorthand struct initialization syntax to pass attributes into elements and components. We got tired of passing class: class
everywhere and decided to finally implement this long awaited feature, at the expense of some code breakage. Now, it’s super simple to declare attributes from props:
#[component]
fn ImgPlus(class: String, id: String, src: String) -> Element {
rsx! {
img { class, id, src }
}
}
This feature works for anything implementing IntoAttribute
, meaning signals also benefit from shorthand initialization. While signals as attributes don’t yet skip diffing, we plan to add this as a performance optimization throughout the 0.5 release cycle.
Another amazing feature added this cycle was attribute merging. When working with libraries like tailwind, you’ll occasionally want to make certain attributes conditional. Before, you had to format the attribute using an empty string. Now, you can simply add an extra attribute with a conditional, and the attribute will be merged using a space as a delimiter:
#[component]
fn Blog(enabled: bool) -> Element {
rsx! {
div {
class: "bg-gray-200 border rounded shadow",
class: if enabled { "text-white" }
}
}
}
This is particularly important when using libraries like tailwind where attributes need to be parsed at compile time but also dynamic at runtime. This syntax integrates with the tailwind compiler, removing the runtime overhead for libraries like tailwind-merge.
Dioxus 0.5 supports the latest version of the server functions crate which supports streaming data. Server functions can now choose to stream data to or from the client. This makes it easier to do a whole class of tasks on the server.
Creating a streaming server function is as easy as defining the output type and returning a TextStream from the server function. Streaming server functions are great for updating the client during any long running task.
We built an AI text generation example here: https://github.com/ealmloff/dioxus-streaming-llm that uses Kalosm and local LLMS to serve what is essentially a clone of OpenAI’s ChatGPT endpoint on commodity hardware.
#[server(output = StreamingText)]
pub async fn mistral(text: String) -> Result<TextStream, ServerFnError> {
let text_generation_stream = todo!();
Ok(TextStream::new(text_generation_stream))
}
https://github.com/DioxusLabs/dioxus/assets/66571940/251f6bf8-4337-4781-a9b4-a22b60ab856e
Side note, the AI metaframework used here - Kalosm - is maintained by the Dioxus core team member ealmloff, and his AI GUI app Floneum is built with Dioxus!
The CLI now supports a fullstack
platform with hot reloading and parallel builds for the client and sever. You can now serve your fullstack app with the dx
command:
dx serve
# Or with an explicit platform
dx serve --platform fullstack
https://github.com/DioxusLabs/dioxus/pull/1505
@DonAlonzo added liveview support for the router in dioxus 0.5. The router will now work out of the box with your liveview apps!
https://github.com/DioxusLabs/dioxus/pull/1719
@willcrichton added support for custom asset handlers to dioxus desktop. Custom asset handlers let you efficiently stream data from your rust code into the browser without going through javascript. This is great for high bandwidth communication like video streaming:
https://github.com/DioxusLabs/dioxus/assets/66571940/ab5fa136-166a-44e3-9053-42418ca45439
Now, you can do things like work with gstreamer or webrtc and pipe data directly into the webview without needing to encode/decode frames by hand.
This is a bit smaller of a tweak, but now we properly support file drops for desktop:
https://github.com/DioxusLabs/dioxus/assets/66571940/e78ddc32-3f30-4a8c-9053-37b592a13cf6
Previously we just gave you the option to intercept filedrops but now it’s natively integrated into the event systme.
Error handling: You can use error boundaries and the throw trait to easily handle errors higher up in your app
Dioxus provides a much easier way to handle errors: throwing them. Throwing errors combines the best parts of an error state and early return: you can easily throw an error with ?
, but you keep information about the error so that you can handle it in a parent component.
You can call throw
on any Result
type that implements Debug
to turn it into an error state and then use ?
to return early if you do hit an error. You can capture the error state with an ErrorBoundary
component that will render the a different component if an error is thrown in any of its children.
fn Parent() -> Element {
rsx! {
ErrorBoundary {
handle_error: |error| rsx! {
"Oops, we encountered an error. Please report {error} to the developer of this application"
},
ThrowsError {}
}
}
}
fn ThrowsError() -> Element {
let name: i32 = use_hook(|| "1.234").parse().throw()?;
todo!()
}
You can even nest ErrorBoundary
components to capture errors at different levels of your app.
fn App() -> Element {
rsx! {
ErrorBoundary {
handle_error: |error| rsx! {
"Hmm, something went wrong. Please report {error} to the developer"
},
Parent {}
}
}
}
fn Parent() -> Element {
rsx! {
ErrorBoundary {
handle_error: |error| rsx! {
"The child component encountered an error: {error}"
},
ThrowsError {}
}
}
}
fn ThrowsError() -> Element {
let name: i32 = use_hook(|| "1.234").parse().throw()?;
todo!()
}
This pattern is particularly helpful whenever your code generates a non-recoverable error. You can gracefully capture these "global" error states without panicking or handling state for each error yourself.
We shipped hotreloading in 0.3, added it to desktop in 0.4, and now we’re finally enabling it by default in 0.5. By default, when you dx serve
your app, hotreloading is enabled in development mode.
Additionally, we’ve drastically improved the developer experience of building desktop apps. When we can’t hotreload the app and have to do a full recompile, we now preserve the state of the open windows and resume that state. This means your app won’t block your entire screen on every edit and it will maintain its size and position, leading to a more magical experience. Once you’ve played with it, you can never go back - it’s that good.
https://github.com/DioxusLabs/dioxus/assets/66571940/21dfca22-14ea-47f9-a2de-9853609a9dd4
With this update, our newest core team member Miles (lovingly, @Doge on our discord) put serious work into overhauling documentation and our templates. We now have templates to create new dioxus apps for web, desktop, mobile, tui, and fullstack under one command.
https://github.com/DioxusLabs/dioxus/assets/66571940/7c6062ea-22a4-4c2a-bd7e-ca6f28cf1dbf
We also updated the default app you get when using dx new
to be closer to the traditional create-react-app. The template is now seeded with assets, CSS, and some basic deploy configuration. Plus, it includes links to useful resources like dioxus-std, the VSCode Extension, docs, tutorials, and more.
The Dioxus Community is something special: discord members marc and Doge have been hard at working updating important ecosystem crates for the 0.5 release. With this release, important crates like icons, charts, and the dioxus-specific standard library are ready to use right out the gate. The Dioxus Community
project is a new GitHub organization that keeps important crates up-to-date even when the original maintainers step down. If you build a library for Dioxus, we’ll be happy to help maintain it, keeping it at what is essentially “Tier 2” support.
At a certain point we had to stop adding new features to this release. There’s plenty of cool projects on the horizon:
.wasm
directly - with lazy componentsWe’re not going to say much about this now, but here’s a sneak peek at “Blitz 2.0”… we’re finally integrating servo into blitz so you can render natively with WGPU using the same CSS engine that powers Firefox. To push this effort forward, we’ve brought the extremely talented Nico Burns (the wizard behind our layout library Taffy) on full time. More about this later, but here’s a little demo of google.com being rendered at 900 FPS entirely on the GPU:
Admittedly the current iteration is not quite there (google.com is in fact a little wonky) but we’re progressing rapidly here and are quickly approaching something quite usable. The repo is here if you want to take a look and get involved:
https://github.com/jkelleyrtp/stylo-dioxus
Well, that’s it for the new features. We might’ve missed a few things (there’s so much new!). If you find Dioxus as exciting as we do, we’d love your help to completely transform app development. We’d love contributions including:
That’s it! We’re super grateful for the community support and excited for the rest of 2024.
Build cool things! ✌️
.gitignore
by @Exotik850 in https://github.com/DioxusLabs/dioxus/pull/1704
lazynodes
module docs by @tigerros in https://github.com/DioxusLabs/dioxus/pull/1759
TaskId
by @Exotik850 in https://github.com/DioxusLabs/dioxus/pull/1710
--split-line-attributes
parameter for CLI fmt
by @marc2332 in https://github.com/DioxusLabs/dioxus/pull/1701
dx create
by @tkr-sh in https://github.com/DioxusLabs/dioxus/pull/1803
init
subcommand by @hem1t in https://github.com/DioxusLabs/dioxus/pull/1840
Config::rootelement
by @mirkootter in https://github.com/DioxusLabs/dioxus/pull/1851
isComposing
support by @egegungordu in https://github.com/DioxusLabs/dioxus/pull/1863
cargo-generate
by @Andrew15-5 in https://github.com/DioxusLabs/dioxus/pull/1873
out_dir
and asset_dir
fields to methods in CrateConfig
(cli-config refactor) by @Andrew15-5 in https://github.com/DioxusLabs/dioxus/pull/1882
release
build option by @Andrew15-5 in https://github.com/DioxusLabs/dioxus/pull/1900
dx build
by @Andrew15-5 in https://github.com/DioxusLabs/dioxus/pull/1898
dx serve
by @Andrew15-5 in https://github.com/DioxusLabs/dioxus/pull/1903
HasFileData
for WebDragData
by @spookyvision in https://github.com/DioxusLabs/dioxus/pull/1917
eval
should not return an error - eval() should always be available by @jkelleyrtp in https://github.com/DioxusLabs/dioxus/pull/1940
Routable
macro by @tigerros in https://github.com/DioxusLabs/dioxus/pull/1975
dioxus-router
docs by @marc2332 in https://github.com/DioxusLabs/dioxus/pull/1983
Resource::clear()
and also updated Resource
docs by @marc2332 in https://github.com/DioxusLabs/dioxus/pull/2049
Published by jkelleyrtp 8 months ago
v0.5 is coming soon! We've decided to start putting out pre-releases so developers on the "bleeding-edge" have a stable checkpoint to use as we release new breaking features.
The full release notes for 0.5 are here:
Migration guide:
https://ealmloff.github.io/docsite/learn/0.4/migration/
Feel free to hop into the discord to give feedback and/or chat about the new changes.
Full Changelog: https://github.com/DioxusLabs/dioxus/compare/v0.4.3...v0.5.0-alpha.0
Published by jkelleyrtp 8 months ago
This is the last release of the 0.4 cycle, containing a number of useful new features as well as many bug fixes.
You can now manipulate the dioxus runtime without going through the Scope
object.
This was originally released many months ago, but we never made the release post.
pre_cache_static_routes
function. by @photon-garden in https://github.com/DioxusLabs/dioxus/pull/1401
onmounted
by @oxkitsune in https://github.com/DioxusLabs/dioxus/pull/1453
Routable
improvements by @tigerros in https://github.com/DioxusLabs/dioxus/pull/1461
gen
in PartialEq
for UseSharedState
by @DanielAlbl in https://github.com/DioxusLabs/dioxus/pull/1389
#[component]
attribute by @tigerros in https://github.com/DioxusLabs/dioxus/pull/1448
dioxus-hooks
modules to use snake_case by @tigerros in https://github.com/DioxusLabs/dioxus/pull/1498
dioxus-core-macro
README as per #1448 by @tigerros in https://github.com/DioxusLabs/dioxus/pull/1510
resouces
by @srid in https://github.com/DioxusLabs/dioxus/pull/1516
tauri-mobile
-> cargo-mobile2
by @amrbashir in https://github.com/DioxusLabs/dioxus/pull/1518
use_on_mount
and fix some typos by @tigerros in https://github.com/DioxusLabs/dioxus/pull/1497
dx serve
in desktop apps by @srid in https://github.com/DioxusLabs/dioxus/pull/1515
#[inline_props]
or #[component]
by @tigerros in https://github.com/DioxusLabs/dioxus/pull/1563
#[component]
expansion Clippy warning by @tigerros in https://github.com/DioxusLabs/dioxus/pull/1599
AtomState::current()
by @marc2332 in https://github.com/DioxusLabs/dioxus/pull/1609
#[derive(Props)]
using const generics by @syrflover in https://github.com/DioxusLabs/dioxus/pull/1607
dioxus-cli
within a workspace (wildcard-members, real package names) by @RGafiyatullin in https://github.com/DioxusLabs/dioxus/pull/1642
backdrop-filter
attribute by @tigerros in https://github.com/DioxusLabs/dioxus/pull/1660
render_handler_with_state
by @sd2k in https://github.com/DioxusLabs/dioxus/pull/1687
Full Changelog: https://github.com/DioxusLabs/dioxus/compare/v0.4.2...v0.4.3
Published by jkelleyrtp 11 months ago
default-features
warning by @eventualbuddha in https://github.com/DioxusLabs/dioxus/pull/1296
check
module alongside others by @eventualbuddha in https://github.com/DioxusLabs/dioxus/pull/1304
Instant::elapsed
by @eventualbuddha in https://github.com/DioxusLabs/dioxus/pull/1307
--profile
to identify cargo build artifact if present for dx cli web builds by @swpecht in https://github.com/DioxusLabs/dioxus/pull/1344
Guide
instead of 0.3 by @Dillon-Roller in https://github.com/DioxusLabs/dioxus/pull/1370
Full Changelog: https://github.com/DioxusLabs/dioxus/compare/v0.4.0...v0.4.2
Published by ealmloff about 1 year ago
check
module alongside others by @eventualbuddha in https://github.com/DioxusLabs/dioxus/pull/1304
Instant::elapsed
by @eventualbuddha in https://github.com/DioxusLabs/dioxus/pull/1307
--profile
to identify cargo build artifact if present for dx cli web builds by @swpecht in https://github.com/DioxusLabs/dioxus/pull/1344
Published by ealmloff about 1 year ago
The Dioxus 0.4 release includes 6 new crates, a ton of new features and a plethora of bug fixes!
Highlights:
The router has been revamped for the 0.4 release. The router now uses an enum to define routes. If you use this enum to link to a page, the compiler will insure you never link to a page that doesn’t exist. The new router also includes Nesting, Layout, and sitemap support:
use dioxus::prelude::*;
use dioxus_router::prelude::*;
#[derive(Routable, Clone)]
enum Route {
#[route("/")]
Home {},
#[route("/blog")]
Blog {},
}
fn App(cx: Scope) -> Element {
render! {
Router::<Route> {}
}
}
#[inline_props]
fn Home(cx: Scope) -> Element {
render! {
Link {
to: Route::Blog {},
"Go to the blog"
}
h1 { "Welcome to the Dioxus Blog!" }
}
}
#[inline_props]
fn Blog(cx: Scope) -> Element {
render! {
Link {
to: Route::Home {},
"Go to the home page"
}
h1 { "Blog" }
}
}
Huge shoutout to @TeFiLeDo for creating many different prototypes and tests for the new router!
The 0.4 release introduces the Fullstack crate. The fullstack crate contains adapters for communicating with your
The fullstack crate makes it dead simple to create a server side rendered hydrated app with fullstack typesafety. The fullstack crate lets you render your page on the server on every request (or incrementally) and then hydrate it on the client.
use dioxus::prelude::*;
use dioxus_fullstack::prelude::*;
fn main() {
LaunchBuilder::new(app).launch();
}
fn app(cx: Scope) -> Element {
let mut count = use_state(cx, || 0);
render! {
h1 { "High-Five counter: {count}" }
button { onclick: move |_| count += 1, "Up high!" }
button { onclick: move |_| count -= 1, "Down low!" }
}
}
In addition to fullstack rendering, the new fullstack create allows you to communicate with your server effortlessly. You can annotate a function with #[server]
to make the code inside the function only run on the server. This makes it easy to build a backend for your web or desktop application!
use dioxus::prelude::*;
use dioxus_fullstack::prelude::*;
fn main() {
LaunchBuilder::new(app).launch();
}
fn app(cx: Scope) -> Element {
let mut count = use_state(cx, || 0);
render! {
h1 { "High-Five counter: {count}" }
button { onclick: move |_| count += 1, "Up high!" }
button { onclick: move |_| count -= 1, "Down low!" }
button {
onclick: move |_| {
to_owned![count];
async move {
let double = double(*count).await.unwrap();
count.set(double);
}
}
}
}
}
#[server]
async fn double(number: usize) -> Result<usize, ServerFnError> {
// This will *only* run on the server
Ok(number * 2)
}
0.4 adds the long awaited suspense feature. This allows you to wait for a future on the server and then send the result to the client. You can combine suspense with server functions to wait for some code on your server to finish running before rendering a component:
use dioxus::prelude::*;
use dioxus_fullstack::prelude::*;
fn main() {
LaunchBuilder::new(app).launch();
}
fn app(cx: Scope) -> Element {
let mut server_data = use_server_future(cx, || get_server_data())?;
render! {
div {
"{server_data:?}"
}
}
}
#[server]
async fn get_server_data() -> Result<usize, ServerFnError> {
Ok(42)
}
The Dioxus CLI has moved into the dioxus main repo
The Dioxus CLI is now called dx
instead of dioxus
. The 0.4 release of the Dioxus CLI added three main features:
@eventualbuddha has done a fantastic job creating a new Dioxus check command to lint your Dioxus code for errors! It will warn you if your code violates the rules of hooks
dx check
The Dioxus CLI can now create installers for MacOs and Windows powered by tauri-bundle!
dioxus bundle
In Dioxus 0.4, rsx hot reloading has moved from the hot reload macro to the CLI for desktop, liveview, fullstack, and TUI applications. Now every platform can use the CLI to start hot reloading:
dioxus serve --platform desktop --hot-reload
Dioxus now has improved mobile support with a getting started guide and a mobile example!
The documentation has been revamped for the 0.4 release. We now have a short getting started guide that teaches you how to build a hackernews clone in Dioxus.
The new documentation site takes full advantage of the fullstack crate to prerender the pages.
While working on the new docsite we also created two new crates:
Together these crates allow us to make our documentation fully interactive and instantly searchable. The new documentation site contains live code snippets of different components as you walk through the guide.
One of the biggest problems with cross platform development in rust today is finding ergonomic ways to interact with system APIs. @doge and @marc have created a new Dioxus std create that makes it easy to interact with a variety of system APIs in Dioxus across all platforms. It contains helpers for Geolocation, clipboard access, notifications, color schemes, translation, and more!
@doge has made the use_eval hook significantly more powerful for the 0.4 release of Dioxus. You can now send messages to and from Javascript asynchronously. This feature makes it possible to listen for Javascript events that Dioxus doesn’t officially support (for example the intersection observer API).
The 0.4 release introduces file upload support for the dioxus-html crate. This makes it easy to upload files to you desktop, liveview, or web application.
This release also introduces a new onmounted event that provides access to some common node APIs like focusing an element or getting the size of an element in a cross platform way.
Dioxus' TUI renderer Rink and WGPU renderer Blitz can now be used without Dioxus. This makes it possible to render your own html into either of these renderers or use these renderers in your own framework. To get started, see the Blitz and Rink framework-less examples.
Dioxus now holds weekly office hours in the discord! If you are interested in the project, need help with your projects, or want to get started contributing, you should come to our weekly office hours!
The office hours happen every Friday at 9:00 AM (PDT) in the Dioxus discord server
Recordings of office hours are available on the Dioxus youtube channel
There have been almost 50 new contributors since the 0.3 release!
@mirkootter, @davidpdrsn, @mwcz, @askreet, @marcerhans, @ndarilek, @arniu, @pickfire, @arqalite, @ProfXwing, @Icekey, @willothy, @rtwfroody, @attilio, @stephenandary, @Rigellute, @onweru, @Byron, @nicoburns, @serzhiio, @indiv0, @azriel91, @elliotwaite, @nmlt, @nicholastmosher, @TimothyStiles, @jpearnshaw, @jmsfltchr, @striezel, @echochamber, @xinglixing, @sean, @torsteingrindvik, @vanhouc, @terhechte, @traxys, @Mouradost, @DianQK, @eventualbuddha, @leahiel, @kaid, @frisoft, @Niedzwiedzw
For more information on the 0.4 release and all the new features that have been introduced, read the blogpost
Full Changelog: https://github.com/DioxusLabs/dioxus/compare/v0.3.2...v0.4.0
Published by ealmloff over 1 year ago
Dioxus 0.3 is bringing a lot of fantastic new features:
For more details about each of these new improvements see the release blog post
Published by jkelleyrtp over 2 years ago
This update is just a minor bump to Dioxus. A ton of bugs were fixed, and a few new features were added.
Notably
A bunch of bugs were fixed too!
Overall, this release will improve the stability, performance, and usability of Dioxus without any major breaking changes.
rsx!
errors by @overlisted in https://github.com/DioxusLabs/dioxus/pull/322
#[inline_props]
generics by @overlisted in https://github.com/DioxusLabs/dioxus/pull/324
cli
docs by @mrxiaozhuox in https://github.com/DioxusLabs/dioxus/pull/380
Full Changelog: https://github.com/DioxusLabs/dioxus/compare/v0.2.0...v0.2.4
Published by jkelleyrtp over 2 years ago
March 9, 2022
Thanks to these amazing folks for their financial support on OpenCollective:
Thanks to these amazing folks for their code contributions:
Just over two months in, and we already a ton of awesome changes to Dioxus!
Dioxus is a recently-released library for building interactive user interfaces (GUI) with Rust. It is built around a Virtual DOM, making it portable for the web, desktop, server, mobile, and more. Dioxus looks and feels just like React, so if you know React, then you'll feel right at home.
fn app(cx: Scope) -> Element {
let mut count = use_state(&cx, || 0);
cx.render(rsx! {
h1 { "Count: {count}" }
button { onclick: move |_| count += 1, "+" }
button { onclick: move |_| count -= 1, "-" }
})
}
A ton of stuff happened in this release; 550+ commits, 23 contributors, 2 minor releases, and 6 backers on Open Collective.
Some of the major new features include:
We also fixed and improved a bunch of stuff - check out the full list down below.
When Dioxus was initially released, we had very simple support for logging Dioxus elements out as TUI elements. In the past month or so, @Demonthos really stepped up and made the new crate a reality.
We totally revamped the router, switching away from the old yew-router approach to the more familiar React-Router. It's less type-safe but provides more flexibility and support for beautiful URLs.
Apps with routers are really simple now. It's easy to compose the "Router", a "Route", and "Links" to define how your app is laid out:
fn app(cx: Scope) -> Element {
cx.render(rsx! {
Router {
onchange: move |_| log::info!("Route changed!"),
ul {
Link { to: "/", li { "Go home!" } }
Link { to: "users", li { "List all users" } }
Link { to: "blog", li { "Blog posts" } }
}
Route { to: "/", "Home" }
Route { to: "/users", "User list" }
Route { to: "/users/:name", User {} }
Route { to: "/blog", "Blog list" }
Route { to: "/blog/:post", BlogPost {} }
Route { to: "", "Err 404 Route Not Found" }
}
})
}
We're also using hooks to parse the URL parameters and segments so you can interact with the router from anywhere deeply nested in your app.
#[derive(Deserialize)]
struct Query { name: String }
fn BlogPost(cx: Scope) -> Element {
let post = use_route(&cx).segment("post")?;
let query = use_route(&cx).query::<Query>()?;
cx.render(rsx!{
"Viewing post {post}"
"Name selected: {query}"
})
}
Give a big thanks to @autarch for putting in all the hard work to make this new router a reality.
The Router guide is available here - thanks to @dogedark.
Managing state in your app can be challenging. Building global state management solutions can be even more challenging. For the first big attempt at building a global state management solution for Dioxus, we chose to keep it simple and follow in the footsteps of the Recoil.JS project.
Fermi uses the concept of "Atoms" for global state. These individual values can be get/set from anywhere in your app. Using state with Fermi is basically as simple as use_state
.
// Create a single value in an "Atom"
static TITLE: Atom<&str> = |_| "Hello";
// Read the value from anywhere in the app, subscribing to any changes
fn app(cx: Scope) -> Element {
let title = use_read(&cx, TITLE);
cx.render(rsx!{
h1 { "{title}" }
Child {}
})
}
// Set the value from anywhere in the app
fn Child(cx: Scope) -> Element {
let set_title = use_set(&cx, TITLE);
cx.render(rsx!{
button {
onclick: move |_| set_title("goodbye"),
"Say goodbye"
}
})
}
For internal components, explicitly declaring props structs can become tedious. That's why we've built the new inline_props
macro. This macro lets you inline your props definition right into your component function arguments.
Simply add the inline_props
macro to your component:
#[inline_props]
fn Child<'a>(
cx: Scope,
name: String,
age: String,
onclick: EventHandler<'a, ClickEvent>
) -> Element {
cx.render(rsx!{
button {
"Hello, {name}"
"You are {age} years old"
onclick: move |evt| onclick.call(evt)
}
})
}
You won't be able to document each field or attach attributes so you should refrain from using it in libraries.
Sometimes you don't want to specify every value in a component's props, since there might a lot. That's why the Props
macro now supports optional fields. You can use a combination of default
, strip_option
, and optional
to tune the exact behavior of properties fields.
#[derive(Props, PartialEq)]
struct ChildProps {
#[props(default = "client")]
name: String,
#[props(default)]
age: Option<u32>,
#[props(optional)]
age: Option<u32>,
}
// then to use the accompanying component
rsx!{
Child {
name: "asd",
}
}
We've changed how DOM patching works in Dioxus-Web; now, all of the DOM manipulation code is written in TypeScript and shared between our web, desktop, and mobile runtimes.
On an M1-max, the "create-rows" operation used to take 45ms. Now, it takes a mere 17ms - 3x faster than React. We expect an upcoming optimization to bring this number as low as 3ms.
Under the hood, we have a new string interning engine to cache commonly used tags and values on the Rust <-> JS boundary, resulting in significant performance improvements.
Overall, Dioxus apps are even more snappy than before.
Before and after:
A very welcome change, thanks AGAIN to @mrxiaozhuox is support for imperatively controlling the desktop window from your Dioxus code.
A bunch of new methods were added:
And more!
In addition, Dioxus Desktop now autoresolves asset locations, so you can easily add local images, JS, CSS, and then bundle it into an .app without hassle.
You can now build entirely borderless desktop apps:
Thanks to the amazing work by @mrxiaozhuox, our CLI tool is fixed and working better than ever. The Dioxus-CLI sports a new development server, an HTML to RSX translation engine, a cargo fmt
-style command, a configuration scheme, and much more.
Unlike its counterpart, Trunk.rs
, the dioxus-cli supports running examples and tests, making it easier to test web-based projects and showcase web-focused libraries.
Working with async isn't the easiest part of Rust. To help improve things, we've upgraded async support across the board in Dioxus.
First, we upgraded the use_future
hook. It now supports dependencies, which let you regenerate a future on the fly as its computed values change. It's never been easier to add datafetching to your Rust Web Apps:
fn RenderDog(cx: Scope, breed: String) -> Element {
let dog_request = use_future(&cx, (breed,), |(breed,)| async move {
reqwest::get(format!("https://dog.ceo/api/breed/{}/images/random", breed))
.await
.unwrap()
.json::<DogApi>()
.await
});
cx.render(match dog_request.value() {
Some(Ok(url)) => rsx!{ img { url: "{url}" } },
Some(Err(url)) => rsx!{ span { "Loading dog failed" } },
None => rsx!{ "Loading dog..." }
})
}
Additionally, we added better support for coroutines. You can now start, stop, resume, and message with asynchronous tasks. The coroutine is automatically exposed to the rest of your app via the Context API. For the vast majority of apps, Coroutines can satisfy all of your state management needs:
fn App(cx: Scope) -> Element {
let sync_task = use_coroutine(&cx, |rx| async move {
connect_to_server().await;
let state = MyState::new();
while let Some(action) = rx.next().await {
reduce_state_with_action(action).await;
}
});
cx.render(rsx!{
button {
onclick: move |_| sync_task.send(SyncAction::Username("Bob")),
"Click to sync your username to the server"
}
})
}
We've covered the major headlining features, but there were so many more!
EventHandler
typeA ton more! Dioxus is now much more stable than it was at release!
Copy
- but now supports Clone for use in async. for_async
has been removedClone
can be sharedDioxus is still under rapid, active development. We'd love for you to get involved! For the next release, we're looking to add:
If you're interested in building an app with Dioxus, make sure to check us out on:
git-repository-url
by @mrxiaozhuox in https://github.com/DioxusLabs/dioxus/pull/123
Chinese
Language Readme
and add some info into README.md by @mrxiaozhuox in https://github.com/DioxusLabs/dioxus/pull/122
dog-app
breed change by @mrxiaozhuox in https://github.com/DioxusLabs/dioxus/pull/138
Issue
template by @mrxiaozhuox in https://github.com/DioxusLabs/dioxus/pull/167
DesktopContext
Wrap & Inject by @mrxiaozhuox in https://github.com/DioxusLabs/dioxus/pull/180
oninput
/onsubmit
by @jkelleyrtp in https://github.com/DioxusLabs/dioxus/pull/147
A
tags in desktop by @jkelleyrtp in https://github.com/DioxusLabs/dioxus/pull/220
===
when rhs is string by @oovm in https://github.com/DioxusLabs/dioxus/pull/241
bool_attr
cannot be use by @mrxiaozhuox in https://github.com/DioxusLabs/dioxus/pull/245
deny(missing_docs)
is many more places by @jkelleyrtp in https://github.com/DioxusLabs/dioxus/pull/272
Dioxus-cli
Document by @mrxiaozhuox in https://github.com/DioxusLabs/dioxus/pull/269
cli
document build by @mrxiaozhuox in https://github.com/DioxusLabs/dioxus/pull/286
trunk
to dioxus-cli
by @mrxiaozhuox in https://github.com/DioxusLabs/dioxus/pull/300
Full Changelog: https://github.com/DioxusLabs/dioxus/compare/v0.1.7...v0.2.0
Published by jkelleyrtp almost 3 years ago
Published by jkelleyrtp almost 3 years ago
handle bool attrs properly
make hydration more robust
overhaul examples and clean things up
more API updates
bubbling
upgrade syntax
events bubble now
support innerhtml
massage lifetimes
support desktop more completely
add update functionality to useref
shared state mechanisms
a cute crm
mutations
select figured out
re-enable suspense
amazingly awesome error handling
proper handling of events
mvoe away from compound context
make hooks free-functions
omg what a dumb mistake
suspense!
bless up, no more segfaults
more suspended nodes!
move over to push based mechanism
architecture document and edit list
it loads the doggos
task system works
but I broke the other things :(
rebuild doesn't return errors
static node infrastructure and ssr changes
enable arbitrary body in rsx! macro
add edits back! and more webview support!
This commit adds a new type - the DomEdit - for serializing the changes made by the diffing machine. The architecture of how DomEdits fit into the cooperative scheduling is still TBD but it will allow us to build change lists without applying them immediately. This is more performant and allows us to only render parts of the page at a time.
This commit also adds more infrastructure around webview. Dioxus can now run on the web, generate static pages, run in the desktop, and run on mobile, with a large part of thanks to webview.
move to slotmap
integrate serialization and string borrowing
This commit adds lifetimes to the diff and realdom methods so consumers may borrow the contents of the DOM for serialization or asynchronous modifications.
events work again!
props memoization is more powerful
This commit solves the memoization , properly memoizing properties that don't have any generic parameters. This is a rough heuristic to prevent non-static lifetimes from creeping into props and breaking our minual lifetime management.
Props that have a generic parameter are opted-out of the partialeq
requirement and props without lifetimes must implement partialeq. We're going to leave manual disabling of memoization for future work.
todomvc
somewhat working with rc and weak
Published by jkelleyrtp almost 3 years ago
Published by jkelleyrtp almost 3 years ago
Published by jkelleyrtp almost 3 years ago
Published by jkelleyrtp almost 3 years ago
Published by jkelleyrtp almost 3 years ago
Published by jkelleyrtp almost 3 years ago
Published by jkelleyrtp almost 3 years ago
EventHandler
typeadd prevent default attribute and upgrade router
make hydration more robust
eanble bubbling
plug in bubbling
more API updates
enable children properly
it works with a new bump each time!!
move back to combined cx/props
bubbling
it compiles once more
should be functional across the boar
wire tasks up
wire up linked nodes
it properly bubbles
upgrade syntax
fake bubbling
events bubble now
pull children out of component definition
cleanuup
full html support
improve FC handling to allow lifetimes of parent
improve safety
massage lifetimes
support desktop more completely
add update functionality to useref
desktop functioning well
shared state mechanisms
mutations
re-enable suspense
amazingly awesome error handling
proper handling of events
keyed diffing!!
update root props
some docs, cleaning
more and more sophisticated diff
a new vnode type for anchors
code quality improvements for core
mvoe away from compound context
wire up resource pool
make hooks free-functions
transition to cx, props
omg what a dumb mistake
suspense!
bless up, no more segfaults
more suspended nodes!
wire up event delegator for webview
fix some lifetime issues
move over to push based mechanism
architecture document and edit list
task system works
but I broke the other things :(
rebuild doesn't return errors
add aria
buff up html allowed attributes
enable components in ssr
keyed diffing
static node infrastructure and ssr changes
tests and benchmarks
dedicated mutations module
refactor out the hooks implementation
fix compiling
move webview to wry
beaf up the use_state hook
namespaced attributes
this commit adds namespaced attributes. This lets us support attribute groups, and thus, inline styles.
This namespaced attribute stuff is only available for styles at the moment, though it theoretically could be enabled for any other attributes.
add edits back! and more webview support!
This commit adds a new type - the DomEdit - for serializing the changes made by the diffing machine. The architecture of how DomEdits fit into the cooperative scheduling is still TBD but it will allow us to build change lists without applying them immediately. This is more performant and allows us to only render parts of the page at a time.
This commit also adds more infrastructure around webview. Dioxus can now run on the web, generate static pages, run in the desktop, and run on mobile, with a large part of thanks to webview.
two calculator examples
move to slotmap
integrate serialization and string borrowing
This commit adds lifetimes to the diff and realdom methods so consumers may borrow the contents of the DOM for serialization or asynchronous modifications.
events work again!
props memoization is more powerful
This commit solves the memoization , properly memoizing properties that don't have any generic parameters. This is a rough heuristic to prevent non-static lifetimes from creeping into props and breaking our minual lifetime management.
Props that have a generic parameter are opted-out of the partialeq
requirement and props without lifetimes must implement partialeq. We're going to leave manual disabling of memoization for future work.
todomvc
somewhat working with rc and weak
dyn scope
update builder
EventHandler
type (be9f1a5)