wip: docs
Worked a bit on adding more examples. Trying out a new "antipattern" example to show how *not* to use Dioxus.
This commit is contained in:
1 parent
9d7ee79826
commit
f5683a2346
9 files changed
+197
-174
No files matched your search
@@ -0,0 +1,62 @@
|
||||
//! Example: Antipatterns
|
||||
//! ---------------------
|
||||
//!
|
||||
//! This example shows what *not* to do and provides a reason why a given pattern is considered an "AntiPattern". Most
|
||||
//! anti-patterns are considered wrong to due performance reasons or violate the "rules" of Dioxus. These rules are
|
||||
//! borrowed from other successful UI frameworks, and Dioxus is more focused on providing a familiar, ergonomic interface
|
||||
//! rather than building new harder-to-misuse patterns.
|
||||
use std::collections::HashMap;
|
||||
|
||||
use dioxus::prelude::*;
|
||||
fn main() {}
|
||||
|
||||
/// Antipattern: Iterators without keys
|
||||
/// -----------------------------------
|
||||
///
|
||||
/// This is considered an anti-pattern for performance reasons. Dioxus must diff your current and old layout and must
|
||||
/// take a slower path if it can't correlate old elements with new elements. Lists are particularly susceptible to the
|
||||
/// "slow" path, so you're strongly encouraged to provide a unique ID stable between renders.
|
||||
///
|
||||
/// Dioxus will log an error in the console if it detects that your iterator does not properly generate keys
|
||||
#[derive(PartialEq, Props)]
|
||||
struct NoKeysProps {
|
||||
data: HashMap<u32, String>,
|
||||
}
|
||||
static AntipatternNoKeys: FC<NoKeysProps> = |cx| {
|
||||
// WRONG: Make sure to add keys!
|
||||
rsx!(in cx, ul {
|
||||
{cx.data.iter().map(|(k, v)| rsx!(li { "List item: {v}" }))}
|
||||
});
|
||||
// Like this:
|
||||
rsx!(in cx, ul {
|
||||
{cx.data.iter().map(|(k, v)| rsx!(li { key: "{k}", "List item: {v}" }))}
|
||||
})
|
||||
};
|
||||
|
||||
/// Antipattern: Deeply nested fragments
|
||||
/// ------------------------------------
|
||||
///
|
||||
/// This particular antipattern is not necessarily an antipattern in other frameworks but does has a performance impact
|
||||
/// in Dioxus apps. Fragments don't mount a physical element to the dom immediately, so Dioxus must recurse into its
|
||||
/// children to find a physical dom node. This process is called "normalization". Other frameworks perform an agressive
|
||||
/// mutative normalization while Dioxus keeps your VNodes immutable. This means that deepely nested fragments make Dioxus
|
||||
/// perform unnecessary work. Prefer one or two levels of fragments / nested components until presenting a true dom element.
|
||||
///
|
||||
/// Only Component and Fragment nodes are susceptible to this issue. Dioxus mitigates this with components by providing
|
||||
/// an API for registering shared state without the ContextProvider pattern.
|
||||
static Blah: FC<()> = |cx| {
|
||||
// Try to avoid
|
||||
rsx!(in cx,
|
||||
Fragment {
|
||||
Fragment {
|
||||
Fragment {
|
||||
Fragment {
|
||||
Fragment {
|
||||
div { "Finally have a real node!" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
};
|
||||
-143
@@ -1,143 +0,0 @@
|
||||
#![allow(unused)]
|
||||
/*
|
||||
This example shows how to encapsulate sate in dioxus components with the reducer pattern.
|
||||
This pattern is very useful when a single component can handle many types of input that can
|
||||
be represented by an enum. This particular pattern is very powerful in rust where ADTs can simplify
|
||||
much of the traditional reducer boilerplate.
|
||||
*/
|
||||
|
||||
fn main() {}
|
||||
use dioxus::prelude::*;
|
||||
use std::future::Future;
|
||||
|
||||
enum Actions {
|
||||
Pause,
|
||||
Play,
|
||||
}
|
||||
|
||||
struct SomeState {
|
||||
is_playing: bool,
|
||||
}
|
||||
|
||||
impl SomeState {
|
||||
fn new() -> Self {
|
||||
Self { is_playing: false }
|
||||
}
|
||||
fn reduce(&mut self, action: Actions) {
|
||||
match action {
|
||||
Actions::Pause => self.is_playing = false,
|
||||
Actions::Play => self.is_playing = true,
|
||||
}
|
||||
}
|
||||
fn is_playing(&self) -> &'static str {
|
||||
match self.is_playing {
|
||||
true => "currently playing!",
|
||||
false => "not currently playing",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub static ExampleReducer: FC<()> = |ctx| {
|
||||
let (state, reduce) = use_reducer(&ctx, SomeState::new, SomeState::reduce);
|
||||
|
||||
let is_playing = state.is_playing();
|
||||
|
||||
ctx.render(rsx! {
|
||||
div {
|
||||
h1 {"Select an option"}
|
||||
h3 {"The radio is... {is_playing}!"}
|
||||
button {
|
||||
"Pause"
|
||||
onclick: move |_| reduce(Actions::Pause)
|
||||
}
|
||||
button {
|
||||
"Play"
|
||||
onclick: move |_| reduce(Actions::Play)
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
struct AppContext {
|
||||
name: String,
|
||||
}
|
||||
|
||||
enum KindaState {
|
||||
Ready,
|
||||
Complete,
|
||||
Erred,
|
||||
}
|
||||
|
||||
static EnumReducer: FC<()> = |ctx| {
|
||||
let (state, reduce) = use_reducer(&ctx, || KindaState::Ready, |cur, new| *cur = new);
|
||||
|
||||
let status = match state {
|
||||
KindaState::Ready => "Ready",
|
||||
KindaState::Complete => "Complete",
|
||||
KindaState::Erred => "Erred",
|
||||
};
|
||||
|
||||
ctx.render(rsx! {
|
||||
div {
|
||||
h1 {"{status}"}
|
||||
button {
|
||||
"Set Ready"
|
||||
onclick: move |_| reduce(KindaState::Ready)
|
||||
}
|
||||
button {
|
||||
"Set Complete"
|
||||
onclick: move |_| reduce(KindaState::Complete)
|
||||
}
|
||||
button {
|
||||
"Set Erred"
|
||||
onclick: move |_| reduce(KindaState::Erred)
|
||||
}
|
||||
ul {
|
||||
{(0..10).map(|f| {
|
||||
|
||||
rsx!{
|
||||
li {
|
||||
"hello there!"
|
||||
}
|
||||
}
|
||||
})}
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
/// Demonstrate how the DebugRenderer can be used to unit test components without needing a browser
|
||||
/// These tests can run locally.
|
||||
/// They use the "compare" method of the debug renderer to do partial tree compares for succint
|
||||
#[test]
|
||||
fn ensure_it_works_properly() -> dioxus::error::Result<()> {
|
||||
let mut test = DebugRenderer::new(EnumReducer);
|
||||
test.compare(rsx! { div { h1 {"Ready"} } })?;
|
||||
|
||||
test.trigger_listener(1)?;
|
||||
test.compare(rsx! { div { h1 {"Ready"} } })?;
|
||||
|
||||
test.trigger_listener(2)?;
|
||||
test.compare(rsx! { div { h1 {"Complete"} } })?;
|
||||
|
||||
test.trigger_listener(3)?;
|
||||
test.compare(rsx! { div { h1 {"Erred"} } })?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
//! Example: Reducer Pattern
|
||||
//! -----------------
|
||||
//! This example shows how to encapsulate sate in dioxus components with the reducer pattern.
|
||||
//! This pattern is very useful when a single component can handle many types of input that can
|
||||
//! be represented by an enum.
|
||||
|
||||
fn main() {}
|
||||
use dioxus::prelude::*;
|
||||
|
||||
pub static ExampleReducer: FC<()> = |ctx| {
|
||||
let (state, reduce) = use_reducer(&ctx, PlayerState::new, PlayerState::reduce);
|
||||
|
||||
let is_playing = state.is_playing();
|
||||
|
||||
ctx.render(rsx! {
|
||||
div {
|
||||
h1 {"Select an option"}
|
||||
h3 {"The radio is... {is_playing}!"}
|
||||
button {
|
||||
"Pause"
|
||||
onclick: move |_| reduce(PlayerAction::Pause)
|
||||
}
|
||||
button {
|
||||
"Play"
|
||||
onclick: move |_| reduce(PlayerAction::Play)
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
enum PlayerAction {
|
||||
Pause,
|
||||
Play,
|
||||
}
|
||||
|
||||
struct PlayerState {
|
||||
is_playing: bool,
|
||||
}
|
||||
|
||||
impl PlayerState {
|
||||
fn new() -> Self {
|
||||
Self { is_playing: false }
|
||||
}
|
||||
fn reduce(&mut self, action: PlayerAction) {
|
||||
match action {
|
||||
PlayerAction::Pause => self.is_playing = false,
|
||||
PlayerAction::Play => self.is_playing = true,
|
||||
}
|
||||
}
|
||||
fn is_playing(&self) -> &'static str {
|
||||
match self.is_playing {
|
||||
true => "currently playing!",
|
||||
false => "not currently playing",
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user