4.7 KiB
obj | website | repo |
---|---|---|
concept | https://dioxuslabs.com | https://github.com/dioxuslabs/dioxus |
Dioxus
Dioxus is a modern, ergonomic, and high-performance Rust framework for building user interfaces using a Virtual DOM (like React). It supports Web, Desktop, TUI, and Mobile targets using a unified component model.
Application
A dioxus app is just a normal rust application. To get started depend on dioxus
and start with this main.rs
:
use dioxus::prelude::*;
fn main() {
dioxus::launch(App);
}
#[component]
pub fn App() -> Element {
rsx! {
p { "Hello World!" }
}
}
Components (RSX)
Dioxus components are Rust functions that return Element
and use the rsx!
macro (similar to JSX). The UI is made with HTML and CSS.
use dioxus::prelude::*;
#[component]
fn App() -> Element {
rsx! {
div {
h1 { "Hello, Dioxus!" }
}
}
}
You can define your own components and take values (Props):
#[component]
fn MyComp(value: String, myevent: EventHandler<MouseEvent>, children: Element) -> Element {
rsx! {
button {
onclick: myevent,
title: value,
{children}
}
}
}
// Usage
#[component]
fn App() -> Element {
rsx! {
MyComp {
// Event Handler
onclick: move |_| { println!("Clicked"); },
// Value
title: "my_title",
// children
p {
"Hello World"
}
}
}
}
Event Handler
Event handling is done inline using closures:
rsx!(
button {
onclick: move |_| println!("Button clicked"),
"Click me"
}
)
Each event handler receives an event struct (e.g., MouseEvent
, FormEvent
).
Hooks
Dioxus has a powerful hook system that allows you to manage state, side effects, and asynchronous operations in your components. With these hooks the UI gets automatically reloaded when needed.
Warning
: Always call the hooks in the same order or they will not work correctly. This means no hooks in loops or conditions.
use_signal
Creates a reactive value that can be read and updated. When the value changes, the component re-renders.
let count = use_signal(|| 0);
rsx! {
button { onclick: move |_| count.set(count() + 1), "Increment" }
p { "Value is {count}" }
}
use_memo
Computes a derived value that only re-evaluates when its dependencies change.
let doubled = use_memo(|| count() * 2);
use_effect
Runs a side effect after the component renders. Useful for operations which should run beside the UI.
use_effect(|| {
// Side effect code here
});
use_resource
Manages an asynchronous resource, such as data fetched from an API.
let resource = use_resource(|| fetch_data());
use_drop
Registers a callback to be run before the component is removed. Useful for cleaning up side effects.
use_drop(|| {
// Cleanup code here
});
Assets
To include assets (like CSS) in our app, you can use the asset!()
macro. This macro ensures the asset will be included in the final app bundle.
static MY_CSS: Asset = asset!("/assets/main.css");
fn App() -> Element {
rsx! {
document::Stylesheet { href: MY_CSS }
}
}
Routing
You can have different routes in your app using dioxus router. To use the router enable the router
feature in the dioxus
crate.
Define the routes:
// All of our routes will be a variant of this Route enum
#[derive(Routable, PartialEq, Clone)]
enum Route {
// if the current location is "/home", render the Home component
#[route("/home")]
Home {},
// if the current location is "/blog", render the Blog component
#[route("/blog")]
Blog {},
}
fn Home() -> Element {
todo!()
}
fn Blog() -> Element {
todo!()
}
To use the router and actually render the routes, add it to your main App component:
fn App() -> Element {
rsx! {
document::Stylesheet { href: asset!("/assets/main.css") }
// Renders the current route
Router::<Route> {}
}
}
To move between routes you can either use a Link
element or the navigator
:
// Link Element
rsx! {
Link { to: Route::Home {}, "Go home!" }
}
// Navigator
rsx! {
button {
onclick: move |_| {
let nav = navigator();
// push
nav.push(Route::Blog {});
// replace
nav.replace(Route::Home {});
// go back
nav.go_back();
// go forward
nav.go_forward();
},
"Go somewhere"
}
}