Claude-skill-registry dioxus-component-patterns
Master Dioxus component patterns and reactive state management. Use when building Dioxus components, managing component state, or implementing component interactions.
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/dioxus-component-patterns" ~/.claude/skills/majiayu000-claude-skill-registry-dioxus-component-patterns && rm -rf "$T"
manifest:
skills/data/dioxus-component-patterns/SKILL.mdsource content
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
for callbacksEventHandler - ✅ 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" } } }