Feat: more ergonomics, more examples

This commit is contained in:
Jonathan Kelley committed 2021-03-26 15:50:28 -04:00
1 parent 44aad2746c
commit 0bcff1f88e
15 files changed
+488 -469

No files matched your search

+152
View File
@@ -0,0 +1,152 @@
/*
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.
*/
#![allow(unused)]
use std::future::Future;
use dioxus::hooks::use_reducer;
use dioxus_ssr::prelude::*;
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, props| {
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, props| {
let (state, reduce) = use_reducer(&ctx, || KindaState::Ready, |cur, new| *cur = new);
let contents = helper(&ctx);
let status = match state {
KindaState::Ready => "Ready",
KindaState::Complete => "Complete",
KindaState::Erred => "Erred",
};
ctx.render(rsx! {
div {
h1 {"{status}"}
{contents}
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!"
}
}
})}
}
}
})
};
fn helper(ctx: &Context) -> DomTree {
ctx.render(rsx! {
div {}
})
}
/// 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(())
}
+73 -19
View File
@@ -1,43 +1,52 @@
use dioxus_ssr::{prelude::*, TextRenderer};
use dioxus_ssr::{
prelude::{builder::IntoDomTree, dioxus::events::on::MouseEvent, *},
TextRenderer,
};
mod components {
mod app;
}
fn main() {
TextRenderer::new(App);
}
#[derive(Debug, PartialEq)]
enum Routes {
enum Route {
Homepage,
ExampleList,
Examples,
}
#[derive(Debug, PartialEq, Props)]
struct AppProps {
route: Routes,
route: Route,
}
trait Blah {}
impl<'a, G> Blah for LazyNodes<'a, G> where G: for<'b> FnOnce(&'b NodeCtx<'a>) -> VNode<'a> + 'a {}
static App: FC<AppProps> = |ctx, props| {
//
let body = rsx! {
div {}
};
let body = match props.route {
Route::Homepage => ctx.render(rsx! {
div {
"Some Content"
}
}),
let top = rsx! {
div {}
Route::Examples => ctx.render(rsx! {
div {
"Other Content"
}
}),
};
ctx.render(rsx!(
div {
Header {}
{body}
{top}
{rsx!{
div {
"you ugl"
}
}}
ul {
{(0..10).map(|f| rsx!{
li {
"this is list item {f}"
}
})}
}
}
))
};
@@ -49,3 +58,48 @@ static Header: FC<()> = |ctx, _| {
}
})
};
mod example {
use super::*;
static ExampleUsage: FC<()> = |ctx, props| {
// direct rsx!
let body = rsx! {
div {}
};
// rendered rsx!
let top = ctx.render(rsx! {
div {
"ack!"
}
});
// listy rsx
let list2 = (0..10).map(|f| {
rsx! {
div {}
}
});
// rendered list rsx
let list = (0..10).map(|f| {
ctx.render(rsx! {
div {}
})
});
ctx.render(rsx!(
div {
Header {}
{body}
{top}
{list}
{list2}
// inline rsx
{rsx!{
div { "hello" }
}}
}
))
};
}