docs: big updates to the reference

This commit is contained in:
Jonathan Kelley committed 2021-07-16 16:11:25 -04:00
1 parent caf772cf24
commit 583fdfa561
57 files changed
+726 -247

No files matched your search

+1 -1
View File
@@ -25,7 +25,7 @@ fn main() {
#[derive(Debug)]
struct CustomContext([&'static str; 3]);
static Example: FC<()> = |cx| {
pub static Example: FC<()> = |cx| {
cx.use_create_context(|| CustomContext(["Jack", "Jill", "Bob"]));
cx.render(rsx! {
+1 -1
View File
@@ -13,7 +13,7 @@ fn main() {
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(Example));
}
static Example: FC<()> = |cx| {
pub static Example: FC<()> = |cx| {
let nodes = (0..500).map(|f| rsx! (li {"div"}));
cx.render(rsx! {
div {
+2 -2
View File
@@ -14,7 +14,7 @@ fn main() {
}
// this is a component
static Example: FC<()> = |cx| {
pub static Example: FC<()> = |cx| {
let (event, set_event) = use_state_classic(cx, || None);
let handler = move |evt| {
@@ -50,7 +50,7 @@ struct ExampleProps {
name: String,
}
static Example2: FC<ExampleProps> = |cx| {
pub static Example2: FC<ExampleProps> = |cx| {
cx.render(rsx! {
div {
h1 {"hello {cx.name}"}
+1 -1
View File
@@ -37,7 +37,7 @@ static App: FC<()> = |cx| {
})
};
static Example: FC<()> = |cx| {
pub static Example: FC<()> = |cx| {
cx.render(rsx! {
div { class: "max-w-lg max-w-xs bg-blue-800 shadow-2xl rounded-lg mx-auto text-center py-12 mt-4 rounded-xl"
div { class: "container py-5 max-w-md mx-auto"
+1 -1
View File
@@ -9,7 +9,7 @@ fn main() {
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(Example))
}
static Example: FC<()> = |cx| {
pub static Example: FC<()> = |cx| {
let (name, set_name) = use_state_classic(cx, || "...?");
log::debug!("Running component....");
+1 -1
View File
@@ -9,7 +9,7 @@ fn main() {
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(Example))
}
static Example: FC<()> = |cx| {
pub static Example: FC<()> = |cx| {
let (name, set_name) = use_state_classic(cx, || "...?");
cx.render(rsx! {
section { class: "py-12 px-4 text-center"
+1 -1
View File
@@ -11,7 +11,7 @@ fn main() {
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(Example));
}
static Example: FC<()> = |cx| {
pub static Example: FC<()> = |cx| {
cx.render(rsx! {
div {
span {
+1 -1
View File
@@ -27,7 +27,7 @@ struct ExampleProps {
initial_name: &'static str,
}
static Example: FC<ExampleProps> = |cx| {
pub static Example: FC<ExampleProps> = |cx| {
let name = use_state(cx, move || cx.initial_name);
cx.render(rsx! {
+1 -1
View File
@@ -1,7 +1,7 @@
use dioxus::prelude::*;
fn main() {}
static Example: FC<()> = |cx| {
pub static Example: FC<()> = |cx| {
let (g, set_g) = use_state(cx, || 0).classic();
let v = (0..10).map(move |f| {
rsx!(li {
+2 -2
View File
@@ -17,7 +17,7 @@ fn main() {
.expect("Webview finished");
}
// static Example: FC<()> = |cx| {
// pub static Example: FC<()> = |cx| {
// cx.render(html! {
// <div>
// <svg class="octicon octicon-star v-align-text-bottom"
@@ -36,7 +36,7 @@ fn main() {
// </div>
// })
// };
static Example: FC<()> = |cx| {
pub static Example: FC<()> = |cx| {
cx.render(rsx! {
div {
class: "flex items-center justify-center flex-col"
+2 -6
View File
@@ -20,12 +20,8 @@ use dioxus::prelude::*;
const STYLE: &str = include_str!("./assets/calculator.css");
fn main() {
dioxus::desktop::launch(App, |cfg| {
cfg.with_title("Calculator Demo")
.with_resizable(true)
.with_skip_taskbar(true)
})
.expect("failed to launch dioxus app");
dioxus::desktop::launch(App, |cfg| cfg.with_title("Calculator Demo"))
.expect("failed to launch dioxus app");
}
static App: FC<()> = |cx| {
+7 -2
View File
@@ -16,8 +16,6 @@
//! Feel free to file a PR or Issue if you run into another antipattern that you think users of Dioxus should know about.
use dioxus::prelude::*;
fn main() {}
/// Antipattern: Iterators without keys
/// -----------------------------------
///
@@ -174,3 +172,10 @@ static _example: FC<()> = |cx| todo!();
/// This will only include the `core` dioxus crate which is relatively slim and fast to compile and avoids target-specific
/// libraries.
static __example: FC<()> = |cx| todo!();
pub static Example: FC<()> = |cx| {
cx.render(rsx! {
AntipatternNoKeys { data: std::collections::HashMap::new() }
AntipatternNestedFragments {}
})
};
-10
View File
@@ -1,10 +0,0 @@
use dioxus::prelude::*;
fn main() {}
static Example: FC<()> = |cx| {
cx.render(rsx! {
div {
}
})
};
+30 -3
View File
@@ -1,10 +1,37 @@
use dioxus::prelude::*;
fn main() {}
//! Example: The basics of Dioxus
//! ----------------------------
//!
//! This small example covers some of the basics of Dioxus including
//! - Components
//! - Props
//! - Children
//! - the rsx! macro
static Example: FC<()> = |cx| {
use dioxus::prelude::*;
pub static Example: FC<()> = |cx| {
cx.render(rsx! {
div {
Greeting {
name: "Dioxus"
div { "Dioxus is a fun, fast, and portable UI framework for Rust" }
}
}
})
};
#[derive(PartialEq, Props)]
struct GreetingProps {
name: &'static str,
}
static Greeting: FC<GreetingProps> = |cx| {
cx.render(rsx! {
div {
h1 { "Hello, {cx.name}!" }
p { "Welcome to the Diouxs framework" }
br {}
{cx.children()}
}
})
};
+2 -3
View File
@@ -17,9 +17,8 @@
//! In the future, this might become a runtime error, so consider it an error today.
use dioxus::prelude::*;
fn main() {}
static App: FC<()> = |cx| {
pub static Example: FC<()> = |cx| {
cx.render(rsx! {
div {
Banner {
@@ -32,7 +31,7 @@ static App: FC<()> = |cx| {
})
};
static Banner: FC<()> = |cx| {
pub static Banner: FC<()> = |cx| {
cx.render(rsx! {
div {
h1 { "This is a great banner!" }
+33 -9
View File
@@ -11,14 +11,12 @@
use dioxus::prelude::*;
fn main() {}
// Convert a boolean conditional into a hide/show
#[derive(PartialEq, Props)]
struct MyProps {
pub struct MyProps {
should_show: bool,
}
static Example: FC<MyProps> = |cx| {
pub static Example0: FC<MyProps> = |cx| {
cx.render(rsx! {
div {
{cx.should_show.then(|| rsx!{
@@ -38,10 +36,10 @@ static Example: FC<MyProps> = |cx| {
// In short:
// `rsx!(in cx, ...)` is shorthand for `cx.render(rsx!(...))`
#[derive(PartialEq, Props)]
struct MyProps1 {
pub struct MyProps1 {
should_show: bool,
}
static Example1: FC<MyProps1> = |cx| {
pub static Example1: FC<MyProps1> = |cx| {
cx.render(rsx! {
div {
// With matching
@@ -70,16 +68,16 @@ static Example1: FC<MyProps1> = |cx| {
/// Matching can be expanded
#[derive(PartialEq)]
enum Color {
pub enum Color {
Green,
Yellow,
Red,
}
#[derive(PartialEq, Props)]
struct MyProps2 {
pub struct MyProps2 {
color: Color,
}
static Example2: FC<MyProps2> = |cx| {
pub static Example2: FC<MyProps2> = |cx| {
cx.render(rsx! {
div {
{match cx.color {
@@ -90,3 +88,29 @@ static Example2: FC<MyProps2> = |cx| {
}
})
};
pub static Example: FC<()> = |cx| {
let should_show = use_state(cx, || false);
let mut color_index = use_state(cx, || 0);
let color = match *color_index % 2 {
2 => Color::Green,
1 => Color::Yellow,
_ => Color::Red,
};
cx.render(rsx! {
div {
button {
onclick: move |_| should_show.set(!*should_show)
"click to toggle showing the examples"
}
button {
onclick: move |_| color_index += 1
"click to for the enxt color"
}
Example0 { should_show: *should_show }
Example1 { should_show: *should_show }
Example2 { color: color }
}
})
};
+28 -1
View File
@@ -1,10 +1,37 @@
use dioxus::prelude::*;
fn main() {}
static Example: FC<()> = |cx| {
pub static Example: FC<()> = |cx| {
cx.render(rsx! {
div {
}
})
};
// A controlled component:
static ControlledSelect: FC<()> = |cx| {
let value = use_state(cx, || String::from("Grapefruit"));
cx.render(rsx! {
select { value: "{value}", onchange: move |evt| value.set(evt.value()),
option { value: "Grapefruit", "Grapefruit"}
option { value: "Lime", "Lime"}
option { value: "Coconut", "Coconut"}
option { value: "Mango", "Mango"}
}
})
};
// TODO - how do uncontrolled things work?
static UncontrolledSelect: FC<()> = |cx| {
let value = use_state(cx, || String::new());
cx.render(rsx! {
select {
option { value: "Grapefruit", "Grapefruit"}
option { value: "Lime", "Lime"}
option { value: "Coconut", "Coconut"}
option { value: "Mango", "Mango"}
}
})
};
+38 -4
View File
@@ -1,10 +1,44 @@
use dioxus::prelude::*;
fn main() {}
//! Example: Web Components & Custom Elements
//! -----------------------------------------
//!
//! Web components are a flavor of html elements that can be user-defined.
//! See: https://www.webcomponents.org for more information.
//!
//! Users who use webcomponents typically don't use Dioxus. However, if you would like to use webcomponents in Dioxus,
//! you can easily create a new custom element with compile-time correct wrappers around the webcomponent.
//!
//! We don't support building new webcomponents with Dioxus, however. :(
static Example: FC<()> = |cx| {
use dioxus::prelude::*;
pub static Example: FC<()> = |cx| {
cx.render(rsx! {
div {
custom_element {
custom_attr: "custom data on custom elements"
}
}
})
};
mod dioxus_elements {
use std::fmt::Arguments;
use dioxus::prelude::DioxusElement;
#[allow(non_camel_case_types)]
pub struct custom_element;
impl DioxusElement for custom_element {
const TAG_NAME: &'static str = "custom_element";
const NAME_SPACE: Option<&'static str> = None;
}
impl custom_element {
pub fn custom_attr<'a>(&self, f: NodeFactory<'a>, val: Arguments) -> Attribute<'a> {
f.attr("custom_asttr", val, None, false)
}
}
// Re-export the normal html namespace
pub use dioxus::prelude::dioxus_elements::*;
use dioxus_core::{nodes::Attribute, NodeFactory};
}
+1 -3
View File
@@ -3,8 +3,6 @@
//!
//! This is a simple pattern that allows you to return no elements!
fn main() {}
use dioxus::prelude::*;
static Example: FC<()> = |cx| cx.render(rsx! { Fragment {} });
pub static Example: FC<()> = |cx| cx.render(rsx! { Fragment {} });
+11 -6
View File
@@ -9,21 +9,18 @@
//! - By using the fragment() method on the node factory
use dioxus::prelude::*;
fn main() {}
// Returning multiple elements with rsx! or html!
static Example1: FC<()> = |cx| {
static App1: FC<()> = |cx| {
cx.render(rsx! {
h1 { }
h2 { }
h3 { }
// {}
// "hello world"
})
};
// Using the Fragment component
static Example2: FC<()> = |cx| {
static App2: FC<()> = |cx| {
cx.render(rsx! {
Fragment {
div {}
@@ -34,7 +31,7 @@ static Example2: FC<()> = |cx| {
};
// Using the `fragment` method on the NodeFactory
static Example3: FC<()> = |cx| {
static App3: FC<()> = |cx| {
cx.render(LazyNodes::new(move |fac| {
fac.fragment_from_iter([
fac.text(format_args!("A")),
@@ -44,3 +41,11 @@ static Example3: FC<()> = |cx| {
])
}))
};
pub static Example: FC<()> = |cx| {
cx.render(rsx! {
App1 {}
App2 {}
App3 {}
})
};
+1 -2
View File
@@ -12,7 +12,6 @@
//! A coming update with the assets system will make it possible to include global css from child components.
use dioxus::prelude::*;
fn main() {}
const STYLE: &str = r#"
body {background-color: powderblue;}
@@ -20,7 +19,7 @@ h1 {color: blue;}
p {color: red;}
"#;
const Example: FC<()> = |cx| {
pub static Example: FC<()> = |cx| {
cx.render(rsx! {
head { style { "{STYLE}" } }
body {
+31 -3
View File
@@ -1,10 +1,38 @@
//! Example: Inline Styles
//! ----------------------
//!
//! This example shows how to use inline styles in Dioxus components.
//!
//! Inline styles function very similar to regular attributes, just grouped together in "style".
//!
//! Inline styles in Dioxus are more performant than React since we're able to cache attributes and compare by pointers.
//! However, it's still not as performant as cascaded styles. Use with care.
use dioxus::prelude::*;
fn main() {}
static Example: FC<()> = |cx| {
pub static Example: FC<()> = |cx| {
cx.render(rsx! {
div {
head {
style: { background_color: "powderblue" }
}
body {
h1 { style: { color: "blue" }
"This is a heading"
}
p { style: { color: "red" }
"This is a paragraph"
}
}
})
};
// .... technically the rsx! macro is slightly broken at the moment and alows styles not wrapped in style {}
// I haven't noticed any name collisions yet, and am tentatively leaving this behavior in..
// Don't rely on it.
static Example2: FC<()> = |cx| {
cx.render(rsx! {
div { color: "red"
"hello world!"
}
})
};
+7 -7
View File
@@ -7,17 +7,17 @@
//! resolves to VNodes. It's more efficient and easier to write than having to `collect` everywhere.
//!
//! This also makes it easy to write "pull"-style iterators that don't have a known size.
fn main() {}
//!
//! However, when the size of an iterator needs to be know for display purposes, collecting is fine.
use dioxus::prelude::*;
static Example: FC<()> = |cx| {
let g = use_state(cx, || 0);
pub static Example: FC<()> = |cx| {
let example_data = use_state(cx, || 0);
let v = (0..10).map(|f| {
rsx! {
li {
onclick: move |_| g.set(f)
li { onclick: move |_| example_data.set(f)
"ID: {f}"
ul {
{(0..10).map(|k| rsx!{
@@ -31,7 +31,7 @@ static Example: FC<()> = |cx| {
});
cx.render(rsx! {
h3 {"Selected: {g}"}
h3 {"Selected: {example_data}"}
ul {
{v}
}
+7 -1
View File
@@ -7,7 +7,13 @@
use dioxus::prelude::*;
fn main() {}
pub static Example: FC<()> = |cx| {
cx.render(rsx! {
ButtonList {}
NonUpdatingEvents {}
DisablePropogation {}
})
};
/// We can use `set_name` in multiple closures; the closures automatically *copy* the reference to set_name.
static ButtonList: FC<()> = |cx| {
+165 -2
View File
@@ -1,7 +1,170 @@
// mod iterator;
// mod memo;
#![allow(
unused,
dead_code,
non_upper_case_globals,
non_camel_case_types,
non_snake_case
)]
mod antipatterns;
mod basics;
mod children;
mod conditional_rendering;
mod controlled_inputs;
mod custom_elements;
mod empty;
mod fragments;
mod global_css;
mod inline_styles;
mod iterators;
mod listener;
mod memo;
mod noderefs;
mod signals;
mod spreadpattern;
mod statemanagement;
mod suspense;
mod task;
mod testing;
mod tostring;
fn main() {}
use std::rc::Rc;
use dioxus::prelude::*;
static App: FC<()> = |cx| {
let (selection, set_selection) = use_state(cx, || None as Option<usize>).classic();
let body = match selection {
Some(id) => rsx!(in cx, ReferenceItem { selected: *id }),
None => rsx!(in cx, div { "Select an concept to explore" }),
};
cx.render(rsx! {
div {
ScrollSelector { onselect: move |id| set_selection(id) }
{body}
}
})
};
// this is its own component to stay memoized
#[derive(Props)]
struct ScrollSelectorProps<'a> {
onselect: &'a dyn Fn(Option<usize>),
}
fn ScrollSelector<'a>(cx: Context<'a, ScrollSelectorProps>) -> VNode<'a> {
let selection_list = (&REFERENCES).iter().enumerate().map(|(id, _)| {
rsx! {
li {
h3 {}
}
}
});
cx.render(rsx! {
div {
h1 {""}
ul {
{selection_list}
button {
onclick: move |_| (cx.onselect)(Some(10))
}
}
}
})
}
#[derive(PartialEq, Props)]
struct ReferenceItemProps {
selected: usize,
}
static ReferenceItem: FC<ReferenceItemProps> = |cx| {
let (caller, name, code) = REFERENCES[cx.selected];
// Create the component using the factory API directly
let caller_node = LazyNodes::new(move |f| f.component(caller, (), None, &[]));
cx.render(rsx! {
div {
// Source of the left, rendered on the right
div {
code { "{code}" }
}
div {
{caller_node}
}
}
})
};
static REFERENCES: &[(FC<()>, &str, &str)] = &[
(basics::Example, "Basics", include_str!("./basics.rs")),
(children::Example, "Children", include_str!("./children.rs")),
(
conditional_rendering::Example,
"Conditional Rendering",
include_str!("./conditional_rendering.rs"),
),
// TODO
(
controlled_inputs::Example,
"Controlled Inputs",
include_str!("./controlled_inputs.rs"),
),
(empty::Example, "empty", include_str!("./empty.rs")),
(
custom_elements::Example,
"Custom Elements & Web Components",
include_str!("./custom_elements.rs"),
),
(
fragments::Example,
"Fragments",
include_str!("./fragments.rs"),
),
(
iterators::Example,
"Iterators",
include_str!("./iterators.rs"),
),
(
global_css::Example,
"Global CSS",
include_str!("./global_css.rs"),
),
(
inline_styles::Example,
"Inline Styles",
include_str!("./inline_styles.rs"),
),
(listener::Example, "Listener", include_str!("./listener.rs")),
(memo::Example, "Memo", include_str!("./memo.rs")),
(
spreadpattern::Example,
"Spread Pattern",
include_str!("./spreadpattern.rs"),
),
(suspense::Example, "Suspense", include_str!("./suspense.rs")),
(task::Example, "Task", include_str!("./task.rs")),
(tostring::Example, "Tostring", include_str!("./tostring.rs")),
(
antipatterns::Example,
"Anti-patterns",
include_str!("./antipatterns.rs"),
),
/*
TODO!
*/
(signals::Example, "Signals", include_str!("./signals.rs")),
(noderefs::Example, "NodeRefs", include_str!("./noderefs.rs")),
(
statemanagement::Example,
"State Management",
include_str!("./statemanagement.rs"),
),
(testing::Example, "Testing", include_str!("./testing.rs")),
];
+8 -9
View File
@@ -18,11 +18,10 @@
//! memoized collections like im-rc which are designed for this use case.
use dioxus::prelude::*;
fn main() {}
// By default, components with no props are always memoized.
// A props of () is considered empty.
static Example: FC<()> = |cx| {
pub static Example: FC<()> = |cx| {
cx.render(rsx! {
div { "100% memoized!" }
})
@@ -32,11 +31,11 @@ static Example: FC<()> = |cx| {
// However, the parent *must* create a new string on every render.
// Notice how these props implement PartialEq - this is required for 'static props
#[derive(PartialEq, Props)]
struct MyProps1 {
pub struct MyProps1 {
name: String,
}
static Example1: FC<MyProps1> = |cx| {
pub static Example1: FC<MyProps1> = |cx| {
cx.render(rsx! {
div { "100% memoized! {cx.name}" }
})
@@ -46,11 +45,11 @@ static Example1: FC<MyProps1> = |cx| {
// In contrast with the `String` example, these props use `Rc<str>` which operates similar to strings in JavaScript.
// These strings cannot be modified, but may be cheaply shared in many places without issue.
#[derive(PartialEq, Props)]
struct MyProps2 {
pub struct MyProps2 {
name: std::rc::Rc<str>,
}
static Example2: FC<MyProps2> = |cx| {
pub static Example2: FC<MyProps2> = |cx| {
cx.render(rsx! {
div { "100% memoized! {cx.name}" }
})
@@ -58,11 +57,11 @@ static Example2: FC<MyProps2> = |cx| {
// These props *do* borrow any content, and therefore cannot be safely memoized!.
#[derive(PartialEq, Props)]
struct MyProps3<'a> {
pub struct MyProps3<'a> {
name: &'a str,
}
// We need to manually specify a lifetime that ensures props and scope (the component's state) share the same lifetime.
// Using the `static Example: FC<()>` pattern _will_ specify a lifetime, but that lifetime will be static which might
// Using the `pub static Example: FC<()>` pattern _will_ specify a lifetime, but that lifetime will be static which might
// not exactly be what you want
fn Example3<'a>(cx: Context<'a, MyProps3<'a>>) -> VNode {
cx.render(rsx! {
@@ -73,7 +72,7 @@ fn Example3<'a>(cx: Context<'a, MyProps3<'a>>) -> VNode {
// These props *do* borrow any content, and therefore cannot be safely memoized!.
// However, they cannot be compared, so we don't need the PartialEq flag.
#[derive(Props)]
struct MyProps4<'a> {
pub struct MyProps4<'a> {
onhandle: &'a dyn Fn(),
}
+1 -1
View File
@@ -1,7 +1,7 @@
use dioxus::prelude::*;
fn main() {}
static Example: FC<()> = |cx| {
pub static Example: FC<()> = |cx| {
cx.render(rsx! {
div {
+1 -1
View File
@@ -1,7 +1,7 @@
use dioxus::prelude::*;
fn main() {}
static Example: FC<()> = |cx| {
pub static Example: FC<()> = |cx| {
cx.render(rsx! {
div {
+4 -5
View File
@@ -8,27 +8,26 @@
//! values, using the manual props as the base and then modifying fields specified with non-spread attributes.
use dioxus::prelude::*;
fn main() {}
static App: FC<()> = |cx| {
pub static Example: FC<()> = |cx| {
let props = MyProps {
count: 0,
live: true,
name: "Dioxus",
};
cx.render(rsx! {
Example { ..props, count: 10, div {"child"} }
Example1 { ..props, count: 10, div {"child"} }
})
};
#[derive(PartialEq, Props)]
struct MyProps {
pub struct MyProps {
count: u32,
live: bool,
name: &'static str,
}
static Example: FC<MyProps> = |cx| {
pub static Example1: FC<MyProps> = |cx| {
cx.render(rsx! {
div {
h1 { "Hello, {cx.name}"}
+1 -1
View File
@@ -1,7 +1,7 @@
use dioxus::prelude::*;
fn main() {}
static Example: FC<()> = |cx| {
pub static Example: FC<()> = |cx| {
cx.render(rsx! {
div {
+11 -42
View File
@@ -1,27 +1,27 @@
//! Example: Suspense
//! -----------------
//! This example shows how the "use_fetch" hook is built on top of Dioxus' "suspense" API. Suspense enables components
//! to wait on futures to complete before rendering the result into VNodes. These VNodes are immediately available in a
//! "suspended" fashion and will automatically propogate to the UI when the future completes.
//! This example demonstrates how the use_suspense hook can be used to load and render asynchronous data. Suspense enables
//! components to wait on futures to complete before rendering the result into VNodes. These VNodes are immediately
//! available in a suspended" fashion and will automatically propogate to the UI when the future completes.
//!
//! Note that if your component updates or receives new props while it is awating the result, the future will be dropped
//! and all work will stop. In this example, we store the future in a hook so we can always resume it.
//! Currently, suspense futures are non-restartable. In the future, we'll provide more granular control of how to start,
//! stop, and reset these futures.
use dioxus::prelude::*;
fn main() {}
#[derive(serde::Deserialize)]
struct DogApi {
message: String,
}
const ENDPOINT: &str = "https://dog.ceo/api/breeds/image/random";
pub static App: FC<()> = |cx| {
let doggo = use_future_effect(cx, move || async move {
match surf::get(ENDPOINT).recv_json::<DogApi>().await {
pub static Example: FC<()> = |cx| {
let doggo = cx.use_suspense(
|| surf::get(ENDPOINT).recv_json::<DogApi>(),
|cx, res| match res {
Ok(res) => rsx!(in cx, img { src: "{res.message}" }),
Err(_) => rsx!(in cx, div { "No doggos for you :(" }),
}
});
},
);
cx.render(rsx!(
div {
@@ -30,34 +30,3 @@ pub static App: FC<()> = |cx| {
}
))
};
// use dioxus_core::virtual_dom::SuspendedContext;
use futures::Future;
use futures::FutureExt;
use std::pin::Pin;
fn use_fetch<'a, T, P, F>(cx: Context<P>, url: &str, g: F) -> VNode<'a>
where
T: serde::de::DeserializeOwned + 'static,
// F: FnOnce(SuspendedContext, surf::Result<T>) -> VNode<'a> + 'a,
F: FnOnce((), surf::Result<T>) -> VNode<'a> + 'a,
{
todo!()
// // essentially we're doing a "use_effect" but with no dependent props or post-render shenanigans
// let fetch_promise = cx.use_hook(
// move || surf::get(url).recv_json::<T>().boxed_local(),
// // just pass the future through
// |p| p,
// |_| (),
// );
// cx.suspend(fetch_promise, g)
}
/// Spawns the future only when the inputs change
fn use_future_effect<'a, 'b, F, P, F2>(cx: Context<P>, g: F2) -> VNode<'a>
where
F: Future<Output = VNode<'b>>,
F2: FnOnce() -> F + 'a,
{
todo!()
}
+61
View File
@@ -0,0 +1,61 @@
//! Example: Tasks
//! --------------
//!
//! Built around the same system that powers suspense, Dioxus also allows users to write arbitrary tasks that can modify
//! state asynchronously. `use_task` takes a future and returns a task handle and an option that holds the tasks's return
//! value. When the task completes, the component will re-render with the result freshly available.
//!
//! Tasks don't necessarily need to complete, however. It would be completely reasonable to wire up a websocket receiver
//! in a task and have it work infinitely while the app is running. If the socket throws an error, the task could complete
//! and the UI could present a helpful error message.
//!
//! Tasks also return the `TaskHandle` type which lets other component logic start, stop, and restart the task at any time.
//! Tasks are very much like an async-flavoroued coroutine, making them incredibly powerful.
//!
//! Tasks must be valid for the 'static lifetime, so any state management neeeds to be cloned into the closure. `use_state`
//! has a method called `for_async` which generates an AsyncUseState wrapper. This has a very similar API to the regualr
//! `use_state` but is `static.
//!
//! Remeber `use_task` is a hook! Don't call it out of order or in loops. You might aaccidentally swap the task handles
//! and break things in subtle ways.
//!
//! Whenever a component is scheduled for deletion, the task is dropped. Make sure that whatever primitives used in the
//! task have a valid drop implementation and won't leave resources tied up.
use dioxus::prelude::*;
pub static Example: FC<()> = |cx| {
let count = use_state(cx, || 0);
let mut direction = use_state(cx, || 1);
// Tasks are 'static, so we need to copy relevant items in
let (async_count, dir) = (count.for_async(), *direction);
let (task, result) = cx.use_task(move || async move {
// Count infinitely!
loop {
gloo_timers::future::TimeoutFuture::new(250).await;
*async_count.get_mut() += dir;
}
});
cx.render(rsx! {
div {
h1 {"count is {count}"}
button {
"Stop counting"
onclick: move |_| task.stop()
}
button {
"Start counting"
onclick: move |_| task.start()
}
button {
"Switch counting direcion"
onclick: move |_| {
direction *= -1;
task.restart();
}
}
}
})
};
+1 -2
View File
@@ -1,7 +1,6 @@
use dioxus::prelude::*;
fn main() {}
static Example: FC<()> = |cx| {
pub static Example: FC<()> = |cx| {
cx.render(rsx! {
div {
+18 -3
View File
@@ -1,10 +1,25 @@
use dioxus::prelude::*;
fn main() {}
use dioxus::ssr;
pub static Example: FC<()> = |cx| {
let as_string = use_state(cx, || {
// Currently, SSR is only supported for whole VirtualDOMs
// This is an easy/low hanging fruit to improve upon
let mut dom = VirtualDom::new(SomeApp);
dom.rebuild_in_place().unwrap();
ssr::render_root(&dom)
});
static Example: FC<()> = |cx| {
cx.render(rsx! {
div {
div { "{as_string}" }
})
};
static SomeApp: FC<()> = |cx| {
cx.render(rsx! {
div { style: {background_color: "blue"}
h1 {"Some amazing app or component"}
p {"Things are great"}
}
})
};
-26
View File
@@ -1,26 +0,0 @@
//! Example: Web Components
//! -----------------------
//!
//! Web components are a flavor of html elements that can be user-defined.
//! See: https://www.webcomponents.org for more information.
//!
//! Users who use webcomponents typically don't use Dioxus. However, if you would like to use webcomponents in Dioxus,
//! you can easily create a new custom element with compile-time correct wrappers around the webcomponent.
//!
//! We don't support building new webcomponents with Dioxus, however.
//!
fn main() {}
mod dioxus_elements {
use dioxus::prelude::DioxusElement;
struct custom_element;
impl DioxusElement for custom_element {
const TAG_NAME: &'static str = "custom_element";
const NAME_SPACE: Option<&'static str> = None;
}
// Re-export the normal html namespace
pub use dioxus::prelude::dioxus_elements::*;
}
+1 -1
View File
@@ -49,7 +49,7 @@ const NONE_ELEMENT: Option<()> = None;
use baller::Baller;
use dioxus::prelude::*;
static Example: FC<()> = |cx| {
pub static Example: FC<()> = |cx| {
let formatting = "formatting!";
let formatting_tuple = ("a", "b");
let lazy_fmt = format_args!("lazily formatted text");
+6 -6
View File
@@ -12,7 +12,7 @@ fn main() {
const STYLE: &str = "body {overflow:hidden;}";
pub const App: FC<()> = |cx| {
pub static App: FC<()> = |cx| {
cx.render(rsx!(
div { class: "overflow-hidden"
style { "{STYLE}" }
@@ -28,7 +28,7 @@ pub const App: FC<()> = |cx| {
))
};
pub const Header: FC<()> = |cx| {
pub static Header: FC<()> = |cx| {
cx.render(rsx! {
div {
header { class: "text-gray-400 bg-gray-900 body-font"
@@ -54,7 +54,7 @@ pub const Header: FC<()> = |cx| {
})
};
pub const Hero: FC<()> = |cx| {
pub static Hero: FC<()> = |cx| {
//
cx.render(rsx! {
section{ class: "text-gray-400 bg-gray-900 body-font"
@@ -92,7 +92,7 @@ pub const Hero: FC<()> = |cx| {
}
})
};
pub const Entry: FC<()> = |cx| {
pub static Entry: FC<()> = |cx| {
//
cx.render(rsx! {
section{ class: "text-gray-400 bg-gray-900 body-font"
@@ -105,7 +105,7 @@ pub const Entry: FC<()> = |cx| {
})
};
pub const StacksIcon: FC<()> = |cx| {
pub static StacksIcon: FC<()> = |cx| {
cx.render(rsx!(
svg {
// xmlns: "http://www.w3.org/2000/svg"
@@ -120,7 +120,7 @@ pub const StacksIcon: FC<()> = |cx| {
}
))
};
pub const RightArrowIcon: FC<()> = |cx| {
pub static RightArrowIcon: FC<()> = |cx| {
cx.render(rsx!(
svg {
fill: "none"
+114
View File
@@ -0,0 +1,114 @@
use dioxus::prelude::*;
use im_rc::HashMap;
use std::rc::Rc;
fn main() {
#[cfg(feature = "desktop")]
// #[cfg(not(target_arch = "wasm32"))]
dioxus::desktop::launch(App, |c| c);
#[cfg(feature = "desktop")]
dioxus::web::launch(App, |c| c);
}
#[derive(PartialEq)]
pub enum FilterState {
All,
Active,
Completed,
}
#[derive(Debug, PartialEq)]
pub struct TodoItem {
pub id: u32,
pub checked: bool,
pub contents: String,
}
const STYLE: &str = include_str!("./_examples/todomvc/style.css");
const App: FC<()> = |cx| {
let draft = use_state(cx, || "".to_string());
let todos = use_state(cx, || HashMap::<u32, Rc<TodoItem>>::new());
let filter = use_state(cx, || FilterState::All);
let todolist = todos
.iter()
.filter(|(id, item)| match *filter {
FilterState::All => true,
FilterState::Active => !item.checked,
FilterState::Completed => item.checked,
})
.map(|(id, todo)| {
rsx!(TodoEntry {
key: "{id}",
todo: todo.clone()
})
})
.collect::<Vec<_>>();
let items_left = todolist.len();
let item_text = match items_left {
1 => "item",
_ => "items",
};
cx.render(rsx! {
div { id: "app"
style {"{STYLE}"}
div {
header { class: "header"
h1 {"todos"}
input {
class: "new-todo"
placeholder: "What needs to be done?"
value: "{draft}"
oninput: move |evt| draft.set(evt.value())
}
}
{todolist}
{(!todos.is_empty()).then(|| rsx!(
footer {
span { strong {"{items_left}"} span {"{item_text} left"} }
ul { class: "filters"
li { class: "All", a { href: "", onclick: move |_| filter.set(FilterState::All), "All" }}
li { class: "Active", a { href: "active", onclick: move |_| filter.set(FilterState::Active), "Active" }}
li { class: "Completed", a { href: "completed", onclick: move |_| filter.set(FilterState::Completed), "Completed" }}
}
}
))}
}
footer { class: "info"
p {"Double-click to edit a todo"}
p { "Created by ", a { "jkelleyrtp", href: "http://github.com/jkelleyrtp/" }}
p { "Part of ", a { "TodoMVC", href: "http://todomvc.com" }}
}
}
})
};
#[derive(PartialEq, Props)]
pub struct TodoEntryProps {
todo: std::rc::Rc<TodoItem>,
}
pub fn TodoEntry(cx: Context<TodoEntryProps>) -> VNode {
let TodoEntryProps { todo } = *cx;
let is_editing = use_state(cx, || false);
let contents = "";
cx.render(rsx! (
li {
"{todo.id}"
input {
class: "toggle"
r#type: "checkbox"
"{todo.checked}"
}
{is_editing.then(|| rsx!{
input {
value: "{contents}"
}
})}
}
))
}