What is Dioxus

Framework for building cross-platform apps(frontend, backend, mobile apps) with the Rust programming language

Terms

Components = Functions

In Dioxus, apps are comprised of individual functions(called Components) that take in some Properties(structures) and render an Element
All Properties(structs) in Dioxus need to derive the Properties trait which requires both Clone and PartialEq

#[component] macro
Dioxus provides the #[component] macro for simplifying how components are defined. This macro converts the parameters of the annotated function into a hidden accompanying struct.
When building apps, you'll frequently use the #[component] macro. When building libraries, we generally suggest deriving Props instead.

Components are rerendered
Just like React, Dioxus will calls component function multiple times throughout its lifecycle
But Why?
it compares the Element returned from the last render against the Element returned in the current render
In Dioxus, re-renders are extremely cheap (much cheaper than React!)

#[derive(Props, PartialEq, Clone)]
struct DogAppProps {
    breed: String
}

fn DogApp(props: DogAppProps) -> Element {
    // ...
}

// This macro converts the parameters of the annotated function into a hidden accompanying struct
#[component]
fn DogApp(breed: String) -> Element {
    // ...
}
        

rsx! {} macro

Dioxus provides the rsx! {} macro for assembling Elements in your app

rsx! {
    if show_title {
        "title!"
    }

    ul {                //for inside ul
        for item in 0..5 {
            "{i}"
        }
    }

    for user in users {
        div {
            key: "{user.id}",       //lists
            "{user.name}"
        }
    }
}
        

Event Handlers

Event handlers are used to respond to user actions. For example, an event handler could be triggered when the user clicks, scrolls, moves the mouse, or types a character.
Event handlers are attached to elements their name usually starts with on- and they accept closures as values.
The closure will be called whenever the event it listens for is triggered and will be passed that event.
Event handlers receive an Event object containing information about the event.

#[component]
fn DogView() -> Element {
    // Closure for event handler
    let save = move |evt| {
        println!("Inside save");
    };

    rsx! {
        div { id: "dogview",
            img { src: "https://images.dog.ceo/breeds/pitbull/dog-3981540_1280.jpg" }
        }
        div { id: "buttons",
        button { onclick: save, id: "save",  "save!" }
        }
    }
}
        

States

App is defined as a function of the current state. As the state changes, the parts of your app that depend on that state will automatically re-run
You can create mutable state in Dioxus with Signals

Local Variables

Signals (local variables)
Signals are used to manage states, Wrap any value inside Signal and do Read/write. There are 2 ways to create signals:
1. Signal::new()
2. use_signal hook (Recommended. cleans the Signal up for you automatically.)

Reactive Primitives
Dioxus, common reactive primitives include:
1. use_state: Manages component state and triggers a re-render when the state changes.
2. use_effect: Executes side effects based on changes to reactive dependencies.
3. use_ref: Maintains mutable references without triggering re-renders
Increment variable on Mouse Click
This will display a button. Everytime we click on button a variable(counter) is incremented.
use_signal

fn main() {
    dioxus::launch(App);
}
fn App() -> Element {
    rsx! {
        button_comp {}
    }
}
fn button_comp() -> Element {
    let mut counter = use_signal(|| 0);

    rsx! {
        button { onclick: move |_oc: Event| {
                // Closure capturing Event data
                counter += 1;
            }, 
            "Button Text" }
        div { "Counter value: {counter}" }
    }
}
                    

// Create a variable(val) & make it 1
let mut val = use_signal(|| 0);
val.set(1);

// Read the variable & modify it
let value = *val.read();
val.set(value + 1);      // Modify afterwards

let value: &mut i32 = &mut val.write();

let a = use_effect(move||{
    val += 1;
});
                    

Global Variables/Global State

Context
Global Signal
Context Global Signal
Variable can be declared in 1 function. Value can be assigned to variable there.
And variable can be used in other function.
App() => Variable Declaration
test_ele() => Variable accessed & Used

use dioxus::prelude::*;
static CSS: Asset = asset!("/assets/main.css");
use std::fmt;

#[derive(Props, PartialEq, Clone, Debug)]
struct Dog {
    breed: String
}
impl fmt::Display for Dog {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "Breed: {}", self.breed)
    }
}
fn main() {
    dioxus::launch(App);
}
fn App() -> Element {
    let a = Dog {           // Declared var here
        breed: "Husky".to_string()
    };
    use_context_provider(||a);
    rsx! {
        test_ele {}
    }
}
fn test_ele() -> Element {
    let name = use_context::();    // Used Var here
    rsx! {
        h1 { "{name}" }
    }
}
                
Declare a global variable and use it in any function

static GLO_NAME:GlobalSignal = Signal::global(|| "Ram".to_string());
fn main() {
    dioxus::launch(App);
}
fn App() -> Element {
    rsx! {
        h1 { "{GLO_NAME}" }
    }
}
                    

Creating a Route

For example, on web, whenever you visit the /favorites url in your browser, the corresponding Favorites page will load.
How to achieve this?

// Add the "Router" feature to the Cargo.toml
$ Cargo.toml
[dependencies]
dioxus = { version = "0.6.0", features = ["fullstack", "router"] } # <----- add "router"

// Dioxus router is defined as an enum with the Routable derive attribute
// Whenever someone reaches root(/), DogView component is rendered
$ main.rs
#[derive(Routable, Clone, PartialEq)]
enum Route {
    #[route("/")]       //route specifics the route's URL
    DogView,
}
fn DogView() -> Element { /* */ }

fn main() {
    dioxus::launch(app);
}
fn app() -> Element {
    rsx! {
        // Now render the Route instead of rendering each component seperately
        Router:: {}
    }
}