Agent skill

dioxus-component-patterns

Master Dioxus component patterns and reactive state management. Use when building Dioxus components, managing component state, or implementing component interactions.

Stars 163
Forks 31

Install this agent skill to your Project

npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/data/dioxus-component-patterns

SKILL.md

Dioxus Component Patterns

Overview

This skill covers component patterns in Dioxus, including component structure, props, state management, event handling, and component composition.

Component Structure

Basic Component

rust
use dioxus::prelude::*;

#[component]
fn ComponentName() -> Element {
    rsx! {
        div {
            "Hello, World!"
        }
    }
}

Component with State

rust
#[component]
fn Counter() -> Element {
    let mut count = use_signal(|| 0);
    
    rsx! {
        div {
            h1 { "Count: {count()}" }
            button {
                onclick: move |_| count.set(count() + 1),
                "Increment"
            }
        }
    }
}

Props Pattern

Simple Props

rust
#[component]
fn Greeting(name: String) -> Element {
    rsx! {
        div {
            "Hello, {name}!"
        }
    }
}

Props with Event Handlers

rust
#[component]
fn ReminderCard(
    reminder: Reminder,
    on_toggle: EventHandler<String>,
    on_delete: EventHandler<String>,
) -> Element {
    let reminder_id = reminder.id.clone();
    
    rsx! {
        div {
            class: "reminder-card",
            h3 { "{reminder.title}" }
            button {
                onclick: move |_| on_toggle.call(reminder_id.clone()),
                "Toggle"
            }
            button {
                onclick: move |_| on_delete.call(reminder_id),
                "Delete"
            }
        }
    }
}

State Management Patterns

Local Component State

rust
#[component]
fn Form() -> Element {
    let mut title = use_signal(|| String::new());
    let mut description = use_signal(|| String::new());
    
    rsx! {
        input {
            value: "{title()}",
            oninput: move |e| title.set(e.value())
        }
    }
}

Shared State via Props

rust
#[component]
fn App() -> Element {
    let mut reminders = use_signal(|| load_reminders());
    
    rsx! {
        ReminderList {
            reminders: reminders(),
            on_update: move |new_reminders| {
                reminders.set(new_reminders);
            }
        }
    }
}

Derived State

rust
#[component]
fn ReminderStats(reminders: Vec<Reminder>) -> Element {
    let total = reminders.len();
    let completed = reminders.iter().filter(|r| r.completed).count();
    let active = total - completed;
    
    rsx! {
        div {
            "Total: {total}, Active: {active}, Completed: {completed}"
        }
    }
}

Event Handling Patterns

Inline Handlers

rust
rsx! {
    button {
        onclick: move |_| {
            count.set(count() + 1);
        },
        "Click"
    }
}

Handler with Event Data

rust
rsx! {
    input {
        oninput: move |e| {
            title.set(e.value());
        }
    }
}

Handler with Cloned Data

rust
#[component]
fn ReminderItem(reminder: Reminder, on_delete: EventHandler<String>) -> Element {
    let reminder_id = reminder.id.clone();
    
    rsx! {
        button {
            onclick: move |_| {
                on_delete.call(reminder_id);
            },
            "Delete"
        }
    }
}

Conditional Rendering

Simple If

rust
rsx! {
    if show_form() {
        AddReminderForm { on_add: move |r| { /* ... */ } }
    }
}

If-Else

rust
rsx! {
    if reminders().is_empty() {
        div { "No reminders yet" }
    } else {
        ReminderList { reminders: reminders() }
    }
}

Ternary-like Pattern

rust
rsx! {
    div {
        class: if is_active() { "active" } else { "inactive" },
        "Content"
    }
}

List Rendering

Simple List

rust
rsx! {
    for reminder in reminders().iter() {
        ReminderCard {
            reminder: reminder.clone(),
            on_toggle: move |id| { /* ... */ },
        }
    }
}

List with Filter

rust
rsx! {
    for reminder in reminders().iter().filter(|r| !r.completed) {
        ReminderCard { reminder: reminder.clone() }
    }
}

List with Index

rust
rsx! {
    for (index, reminder) in reminders().iter().enumerate() {
        ReminderCard {
            reminder: reminder.clone(),
            index: index,
        }
    }
}

Component Composition

Container Component

rust
#[component]
fn App() -> Element {
    let mut reminders = use_signal(|| load_reminders());
    let mut show_form = use_signal(|| false);
    
    rsx! {
        div {
            Header {
                on_new_click: move |_| show_form.set(true)
            }
            if show_form() {
                AddReminderForm {
                    on_add: move |r| { /* ... */ },
                    on_cancel: move |_| show_form.set(false),
                }
            }
            ReminderList {
                reminders: reminders(),
                on_update: move |new| reminders.set(new),
            }
        }
    }
}

Presentational Component

rust
#[component]
fn ReminderList(
    reminders: Vec<Reminder>,
    on_update: EventHandler<Vec<Reminder>>,
) -> Element {
    rsx! {
        div {
            class: "reminder-list",
            for reminder in reminders.iter() {
                ReminderCard {
                    reminder: reminder.clone(),
                    on_toggle: move |id| {
                        let mut updated = reminders.clone();
                        // Update logic
                        on_update.call(updated);
                    },
                }
            }
        }
    }
}

Form Patterns

Controlled Input

rust
#[component]
fn TextInput(value: String, on_change: EventHandler<String>) -> Element {
    rsx! {
        input {
            value: "{value}",
            oninput: move |e| on_change.call(e.value())
        }
    }
}

Form with Validation

rust
#[component]
fn AddReminderForm(on_add: EventHandler<Reminder>) -> Element {
    let mut title = use_signal(|| String::new());
    let mut error = use_signal(|| None::<String>);
    
    rsx! {
        div {
            input {
                value: "{title()}",
                oninput: move |e| {
                    title.set(e.value());
                    if e.value().is_empty() {
                        error.set(Some("Title is required".to_string()));
                    } else {
                        error.set(None);
                    }
                }
            }
            if let Some(err) = error() {
                span { class: "error", "{err}" }
            }
            button {
                disabled: title().is_empty(),
                onclick: move |_| {
                    if !title().is_empty() {
                        on_add.call(Reminder { /* ... */ });
                        title.set(String::new());
                    }
                },
                "Add"
            }
        }
    }
}

Best Practices

DO:

  • ✅ Keep components small and focused
  • ✅ Use descriptive component names
  • ✅ Pass only necessary props
  • ✅ Use EventHandler for callbacks
  • ✅ Clone only what's needed in closures
  • ✅ Use conditional rendering for UI states
  • ✅ Use iterators for list rendering

DON'T:

  • ❌ Don't create signals in render loops
  • ❌ Don't mutate state directly (use .set())
  • ❌ Don't pass entire state to child components
  • ❌ Don't create unnecessary clones
  • ❌ Don't use indices when iterators work
  • ❌ Don't mix concerns in components

Common Patterns

Loading State

rust
let mut loading = use_signal(|| false);

rsx! {
    if loading() {
        div { "Loading..." }
    } else {
        ReminderList { reminders: reminders() }
    }
}

Error State

rust
let mut error = use_signal(|| None::<String>);

rsx! {
    if let Some(err) = error() {
        div { class: "error", "{err}" }
    }
}

Toggle Pattern

rust
let mut is_open = use_signal(|| false);

rsx! {
    button {
        onclick: move |_| is_open.set(!is_open()),
        if is_open() { "Close" } else { "Open" }
    }
    if is_open() {
        div { "Content" }
    }
}

Resources

Didn't find tool you were looking for?

Be as detailed as possible for better results