From 68ca4c3289f3108ffdd6b8e0ad187071d10a110a Mon Sep 17 00:00:00 2001 From: Z Date: Fri, 31 Jan 2025 18:38:24 -0500 Subject: [PATCH] feat(examples): add Context API state management example (#3657) * feat(examples): add Context API state management example (fixes #3612) * refactor: code cleanup --- examples/README.md | 2 + examples/assets/context_api.css | 43 ++++++++++++++++ examples/context_api.rs | 89 +++++++++++++++++++++++++++++++++ 3 files changed, 134 insertions(+) create mode 100644 examples/assets/context_api.css create mode 100644 examples/context_api.rs diff --git a/examples/README.md b/examples/README.md index aafff9c0d..72fe69f1d 100644 --- a/examples/README.md +++ b/examples/README.md @@ -52,6 +52,8 @@ cargo run --example hello_world ### State Management +[context_api](./context_api.rs) - Cross-component state sharing via Context API + ### Async [login_form](./login_form.rs) - Login endpoint example diff --git a/examples/assets/context_api.css b/examples/assets/context_api.css new file mode 100644 index 000000000..42e0f226c --- /dev/null +++ b/examples/assets/context_api.css @@ -0,0 +1,43 @@ +.main-container { + font-family: system-ui, sans-serif; + max-width: 600px; + margin: 2rem auto; + padding: 2rem; +} + +.light-theme { + background: #ffffff; + color: #1a1a1a; + border: 1px solid #e0e0e0; +} + +.dark-theme { + background: #1a1a1a; + color: #ffffff; + border: 1px solid #333; +} + +.controls { + display: flex; + gap: 1rem; + margin: 2rem 0; +} + +.btn { + padding: 0.5rem 1rem; + border: none; + border-radius: 4px; + cursor: pointer; + transition: opacity 0.2s; +} + +.btn:disabled { + opacity: 0.7; + cursor: not-allowed; +} + +.display { + padding: 2rem; + border-radius: 8px; + margin-top: 2rem; +} diff --git a/examples/context_api.rs b/examples/context_api.rs new file mode 100644 index 000000000..e4c2103d9 --- /dev/null +++ b/examples/context_api.rs @@ -0,0 +1,89 @@ +//! Demonstrates cross-component state sharing using Dioxus' Context API +//! +//! Features: +//! - Context provider initialization +//! - Nested component consumption +//! - Reactive state updates +//! - Error handling for missing context +//! - Platform-agnostic implementation + +use dioxus::prelude::*; + +const STYLE: Asset = asset!("/examples/assets/context_api.css"); + +fn main() { + launch(app); +} + +#[component] +fn app() -> Element { + // Provide theme context at root level + use_context_provider(|| Signal::new(Theme::Light)); + + rsx! { + document::Link { rel: "stylesheet", href: STYLE } + main { + class: "main-container", + + h1 { "Theme Switcher" } + ThemeControls {} + ThemeDisplay {} + } + } +} + +#[derive(Clone, Copy, PartialEq, Debug)] +enum Theme { + Light, + Dark, +} + +impl Theme { + fn stylesheet(&self) -> &'static str { + match self { + Theme::Light => "light-theme", + Theme::Dark => "dark-theme", + } + } +} + +#[component] +fn ThemeControls() -> Element { + let mut theme = use_theme_context(); + let current_theme = *theme.read(); + rsx! { + div { + class: "controls", + button { + class: "btn", + onclick: move |_| theme.set(Theme::Light), + disabled: current_theme== Theme::Light, + "Switch to Light" + } + button { + class: "btn", + onclick: move |_| theme.set(Theme::Dark), + disabled: current_theme == Theme::Dark, + "Switch to Dark" + } + } + } +} + +#[component] +fn ThemeDisplay() -> Element { + let theme = use_theme_context(); + + rsx! { + div { + class: "display {theme.read().stylesheet()}", + p { "Current theme: {theme:?}" } + p { "Try switching themes using the buttons above!" } + } + } +} + +fn use_theme_context() -> Signal { + try_use_context::>() + .expect("Theme context not found. Ensure is the root component.") +}