Claude Code Plugins

Community-maintained marketplace

Feedback

dioxus-component-patterns

@wchklaus97/remind-me-pwa
1
0

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

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

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

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

use dioxus::prelude::*;

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

Component with State

#[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

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

Props with Event Handlers

#[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

#[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

#[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

#[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

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

Handler with Event Data

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

Handler with Cloned Data

#[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

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

If-Else

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

Ternary-like Pattern

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

List Rendering

Simple List

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

List with Filter

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

List with Index

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

Component Composition

Container Component

#[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

#[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

#[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

#[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

let mut loading = use_signal(|| false);

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

Error State

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

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

Toggle Pattern

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