feat: massage lifetimes

This commit is contained in:
Jonathan Kelley 2021-10-16 17:37:28 -04:00
parent 16dbf4a6f8
commit 9726a065b0
92 changed files with 250 additions and 241 deletions

View File

@ -49,7 +49,7 @@
Dioxus is a portable, performant, and ergonomic framework for building cross-platform user experiences in Rust. Dioxus is a portable, performant, and ergonomic framework for building cross-platform user experiences in Rust.
```rust ```rust
static App: FC<()> = |cx, props| { static App: FC<()> = |(cx, props)| {
let mut count = use_state(cx, || 0); let mut count = use_state(cx, || 0);
cx.render(rsx!( cx.render(rsx!(
@ -96,28 +96,6 @@ If you know React, then you already know Dioxus.
See the awesome-dioxus page for a curated list of content in the Dioxus Ecosystem. See the awesome-dioxus page for a curated list of content in the Dioxus Ecosystem.
<!--
currently commented out until we have more content on the website
## Explore
- [**Fine-grained reactivity**: Skip the diff overhead with signals ](docs/guides/00-index.md)
- [**HTML Templates**: Drop in existing HTML5 templates with html! macro](docs/guides/00-index.md)
- [**RSX Templates**: Clean component design with rsx! macro](docs/guides/00-index.md)
- [**Running the examples**: Explore the vast collection of samples, tutorials, and demos](docs/guides/00-index.md)
- [**Building applications**: Use the Dioxus CLI to build and bundle apps for various platforms](docs/guides/01-ssr.md)
- [**Liveview**: Build custom liveview components that simplify datafetching on all platforms](docs/guides/01-ssr.md)
- [**State management**: Easily add powerful state management that comes integrated with Dioxus Core](docs/guides/01-ssr.md)
- [**Concurrency**: Drop in async where it fits and suspend components until new data is ready](docs/guides/01-ssr.md)
- [**1st party hooks**: Cross-platform router hook](docs/guides/01-ssr.md)
- [**Community hooks**: 3D renderers](docs/guides/01-ssr.md)
## Blog Posts
- [Why we need a stronger typed web]()
- [Isomorphic webapps in 10 minutes]()
- [Rust is high level too]()
- [Eliminating crashes with Rust webapps]()
- [Tailwind for Dioxus]()
- [The monoglot startup]()
-->
## Why? ## Why?
TypeScript is a great addition to JavaScript, but comes with a lot of tweaking flags, a slight performance hit, and an uneven ecosystem where some of the most important packages are not properly typed. TypeScript provides a lot of great benefits to JS projects, but comes with its own "tax" that can slow down dev teams. Rust can be seen as a step up from TypeScript, supporting: TypeScript is a great addition to JavaScript, but comes with a lot of tweaking flags, a slight performance hit, and an uneven ecosystem where some of the most important packages are not properly typed. TypeScript provides a lot of great benefits to JS projects, but comes with its own "tax" that can slow down dev teams. Rust can be seen as a step up from TypeScript, supporting:
@ -130,7 +108,7 @@ TypeScript is a great addition to JavaScript, but comes with a lot of tweaking f
- integrated documentation - integrated documentation
- inline built-in unit/integration testing - inline built-in unit/integration testing
- best-in-class error handling - best-in-class error handling
- simple and fast build system (compared to webpack!) - simple and fast build system (compared to WebPack!)
- powerful standard library (no need for lodash or underscore) - powerful standard library (no need for lodash or underscore)
- include_str! for integrating html/css/svg templates directly - include_str! for integrating html/css/svg templates directly
- various macros (`html!`, `rsx!`) for fast template iteration - various macros (`html!`, `rsx!`) for fast template iteration

View File

@ -6,7 +6,7 @@
```rust, ignore ```rust, ignore
// An example Dioxus app - closely resembles React // An example Dioxus app - closely resembles React
static App: FC<()> = |cx, props| { static App: FC<()> = |(cx, props)| {
let mut count = use_state(cx, || 0); let mut count = use_state(cx, || 0);
cx.render(rsx!( cx.render(rsx!(

View File

@ -50,8 +50,8 @@ async fn ExampleLoader(cx: Context<()>) -> Vnode {
This API stores the result on the Context object, so the loaded data is taken as reference. This API stores the result on the Context object, so the loaded data is taken as reference.
*/ */
let name: &Result<SomeStructure> = use_fetch_data("http://example.com/json", ()) let name: &Result<SomeStructure> = use_fetch_data("http://example.com/json", ())
.place_holder(|cx, props|rsx!{<div> "loading..." </div>}) .place_holder(|(cx, props)|rsx!{<div> "loading..." </div>})
.delayed_place_holder(1000, |cx, props|rsx!{ <div> "still loading..." </div>}) .delayed_place_holder(1000, |(cx, props)|rsx!{ <div> "still loading..." </div>})
.await; .await;
match name { match name {

View File

@ -21,9 +21,9 @@ fn test() -> DomTree {
} }
} }
static TestComponent: FC<()> = |cx, props|html!{<div>"Hello world"</div>}; static TestComponent: FC<()> = |(cx, props)|html!{<div>"Hello world"</div>};
static TestComponent: FC<()> = |cx, props|{ static TestComponent: FC<()> = |(cx, props)|{
let g = "BLAH"; let g = "BLAH";
html! { html! {
<div> "Hello world" </div> <div> "Hello world" </div>
@ -31,7 +31,7 @@ static TestComponent: FC<()> = |cx, props|{
}; };
#[functional_component] #[functional_component]
static TestComponent: FC<{ name: String }> = |cx, props|html! { <div> "Hello {name}" </div> }; static TestComponent: FC<{ name: String }> = |(cx, props)|html! { <div> "Hello {name}" </div> };
``` ```
## Why this behavior? ## Why this behavior?

View File

@ -96,7 +96,7 @@ Sometimes you want a signal to propagate across your app, either through far-awa
```rust ```rust
const TITLE: Atom<String> = || "".to_string(); const TITLE: Atom<String> = || "".to_string();
const Provider: FC<()> = |cx, props|{ const Provider: FC<()> = |(cx, props)|{
let title = use_signal(&cx, &TITLE); let title = use_signal(&cx, &TITLE);
rsx!(cx, input { value: title }) rsx!(cx, input { value: title })
}; };
@ -105,7 +105,7 @@ const Provider: FC<()> = |cx, props|{
If we use the `TITLE` atom in another component, we can cause updates to flow between components without calling render or diffing either component trees: If we use the `TITLE` atom in another component, we can cause updates to flow between components without calling render or diffing either component trees:
```rust ```rust
const Receiver: FC<()> = |cx, props|{ const Receiver: FC<()> = |(cx, props)|{
let title = use_signal(&cx, &TITLE); let title = use_signal(&cx, &TITLE);
log::info!("This will only be called once!"); log::info!("This will only be called once!");
rsx!(cx, rsx!(cx,
@ -132,7 +132,7 @@ Dioxus automatically understands how to use your signals when mixed with iterato
```rust ```rust
const DICT: AtomFamily<String, String> = |_| {}; const DICT: AtomFamily<String, String> = |_| {};
const List: FC<()> = |cx, props|{ const List: FC<()> = |(cx, props)|{
let dict = use_signal(&cx, &DICT); let dict = use_signal(&cx, &DICT);
cx.render(rsx!( cx.render(rsx!(
ul { ul {

View File

@ -85,7 +85,7 @@ fn main() {
dioxus::desktop::start(App, |c| c); dioxus::desktop::start(App, |c| c);
} }
static App: FC<()> = |cx, props| { static App: FC<()> = |(cx, props)| {
cx.render(rsx! ( cx.render(rsx! (
div { "Hello, world!" } div { "Hello, world!" }
)) ))
@ -111,7 +111,7 @@ fn main() {
Finally, our app. Every component in Dioxus is a function that takes in `Context` and `Props` and returns an `Option<VNode>`. Finally, our app. Every component in Dioxus is a function that takes in `Context` and `Props` and returns an `Option<VNode>`.
```rust ```rust
static App: FC<()> = |cx, props| { static App: FC<()> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
div { "Hello, world!" } div { "Hello, world!" }
}) })
@ -149,7 +149,7 @@ If we wanted to golf a bit, we can shrink our hello-world even smaller:
```rust ```rust
fn main() { fn main() {
static App: FC<()> = |cx, props| rsx!(cx, div {"hello world!"}); static App: FC<()> = |(cx, props)| rsx!(cx, div {"hello world!"});
dioxus::web::start(App, |c| c); dioxus::web::start(App, |c| c);
} }
``` ```

View File

@ -11,7 +11,7 @@ async fn main() {
dioxus::desktop::launch(App, |c| c); dioxus::desktop::launch(App, |c| c);
} }
pub static App: FC<()> = |cx, _| { pub static App: FC<()> = |(cx, _)| {
let count = use_state(cx, || 0); let count = use_state(cx, || 0);
let mut direction = use_state(cx, || 1); let mut direction = use_state(cx, || 1);

View File

@ -20,8 +20,8 @@ fn main() {
dioxus::desktop::launch(App, |c| c); dioxus::desktop::launch(App, |c| c);
} }
fn App<'a>(cx: Context<'a>, props: &()) -> DomTree<'a> { fn App((cx, props): Component<()>) -> DomTree {
let text: &'a mut Vec<String> = cx.use_hook(|_| vec![String::from("abc=def")], |f| f, |_| {}); let text: &mut Vec<String> = cx.use_hook(|_| vec![String::from("abc=def")], |f| f, |_| {});
let first = text.get_mut(0).unwrap(); let first = text.get_mut(0).unwrap();
@ -43,7 +43,7 @@ impl<'a> Drop for C1Props<'a> {
fn drop(&mut self) {} fn drop(&mut self) {}
} }
fn Child1<'a>(cx: Context<'a>, props: &'a C1Props) -> DomTree<'a> { fn Child1<'a>((cx, props): Component<'a, C1Props>) -> DomTree<'a> {
let (left, right) = props.text.split_once("=").unwrap(); let (left, right) = props.text.split_once("=").unwrap();
cx.render(rsx! { cx.render(rsx! {
@ -58,13 +58,8 @@ fn Child1<'a>(cx: Context<'a>, props: &'a C1Props) -> DomTree<'a> {
struct C2Props<'a> { struct C2Props<'a> {
text: &'a str, text: &'a str,
} }
impl<'a> Drop for C2Props<'a> {
fn drop(&mut self) {
todo!()
}
}
fn Child2<'a>(cx: Context<'a>, props: &'a C2Props) -> DomTree<'a> { fn Child2<'a>((cx, props): Component<'a, C2Props>) -> DomTree<'a> {
cx.render(rsx! { cx.render(rsx! {
Child3 { Child3 {
text: props.text text: props.text
@ -77,7 +72,7 @@ struct C3Props<'a> {
text: &'a str, text: &'a str,
} }
fn Child3<'a>(cx: Context<'a>, props: &C3Props) -> DomTree<'a> { fn Child3<'a>((cx, props): Component<'a, C3Props>) -> DomTree<'a> {
cx.render(rsx! { cx.render(rsx! {
div { "{props.text}"} div { "{props.text}"}
}) })

View File

@ -10,7 +10,7 @@ fn main() {
dioxus::desktop::launch(APP, |cfg| cfg); dioxus::desktop::launch(APP, |cfg| cfg);
} }
const APP: FC<()> = |cx, _| { const APP: FC<()> = |(cx, _)| {
let cur_val = use_state(cx, || 0.0_f64); let cur_val = use_state(cx, || 0.0_f64);
let operator = use_state(cx, || None as Option<&'static str>); let operator = use_state(cx, || None as Option<&'static str>);
let display_value = use_state(cx, || String::from("")); let display_value = use_state(cx, || String::from(""));
@ -116,7 +116,7 @@ struct CalculatorKeyProps<'a> {
onclick: &'a dyn Fn(MouseEvent), onclick: &'a dyn Fn(MouseEvent),
} }
fn CalculatorKey<'a>(cx: Context<'a>, props: &'a CalculatorKeyProps) -> DomTree<'a> { fn CalculatorKey<'a>((cx, props): Component<'a, CalculatorKeyProps>) -> DomTree<'a> {
rsx!(cx, button { rsx!(cx, button {
class: "calculator-key {props.name}" class: "calculator-key {props.name}"
onclick: {props.onclick} onclick: {props.onclick}

View File

@ -27,7 +27,7 @@ fn main() {
use dioxus::prelude::*; use dioxus::prelude::*;
static App: FC<()> = |cx, props| { static App: FC<()> = |(cx, props)| {
let p1 = use_state(cx, || 0); let p1 = use_state(cx, || 0);
let p2 = use_state(cx, || 0); let p2 = use_state(cx, || 0);
@ -59,7 +59,7 @@ struct HorseyProps {
pos: i32, pos: i32,
} }
static Horsey: FC<HorseyProps> = |cx, props| { static Horsey: FC<HorseyProps> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
div { div {
button { "pause" } button { "pause" }

View File

@ -19,7 +19,7 @@ pub struct Client {
pub description: String, pub description: String,
} }
static App: FC<()> = |cx, _| { static App: FC<()> = |(cx, _)| {
let clients = use_ref(cx, || vec![] as Vec<Client>); let clients = use_ref(cx, || vec![] as Vec<Client>);
let scene = use_state(cx, || Scene::ClientsList); let scene = use_state(cx, || Scene::ClientsList);

View File

@ -18,7 +18,7 @@ fn main() {
}); });
} }
static App: FC<()> = |cx, props| { static App: FC<()> = |(cx, props)| {
let file_manager = use_ref(cx, || Files::new()); let file_manager = use_ref(cx, || Files::new());
let files = file_manager.read(); let files = file_manager.read();

View File

@ -9,7 +9,7 @@ fn main() {
// We use a special immutable hashmap to make hashmap operations efficient // We use a special immutable hashmap to make hashmap operations efficient
type RowList = im_rc::HashMap<usize, Rc<str>, FxBuildHasher>; type RowList = im_rc::HashMap<usize, Rc<str>, FxBuildHasher>;
static App: FC<()> = |cx, _props| { static App: FC<()> = |(cx, _props)| {
let items = use_state(cx, || RowList::default()); let items = use_state(cx, || RowList::default());
let create_rendered_rows = move |from, num| move |_| items.set(create_row_list(from, num)); let create_rendered_rows = move |from, num| move |_| items.set(create_row_list(from, num));
@ -80,7 +80,7 @@ struct ActionButtonProps<'a> {
onclick: &'a dyn Fn(MouseEvent), onclick: &'a dyn Fn(MouseEvent),
} }
fn ActionButton<'a>(cx: Context<'a>, props: &'a ActionButtonProps) -> DomTree<'a> { fn ActionButton<'a>((cx, props): Component<'a, ActionButtonProps>) -> DomTree<'a> {
rsx!(cx, div { class: "col-sm-6 smallpad" rsx!(cx, div { class: "col-sm-6 smallpad"
button { class:"btn btn-primary btn-block", r#type: "button", id: "{props.id}", onclick: {props.onclick}, button { class:"btn btn-primary btn-block", r#type: "button", id: "{props.id}", onclick: {props.onclick},
"{props.name}" "{props.name}"
@ -93,7 +93,7 @@ struct RowProps {
row_id: usize, row_id: usize,
label: Rc<str>, label: Rc<str>,
} }
fn Row<'a>(cx: Context<'a>, props: &'a RowProps) -> DomTree<'a> { fn Row((cx, props): Component<RowProps>) -> DomTree {
rsx!(cx, tr { rsx!(cx, tr {
td { class:"col-md-1", "{props.row_id}" } td { class:"col-md-1", "{props.row_id}" }
td { class:"col-md-1", onclick: move |_| { /* run onselect */ } td { class:"col-md-1", onclick: move |_| { /* run onselect */ }

View File

@ -19,7 +19,7 @@ fn main() {
dioxus::desktop::launch(App, |c| c.with_prerendered(content)); dioxus::desktop::launch(App, |c| c.with_prerendered(content));
} }
static App: FC<()> = |cx, props| { static App: FC<()> = |(cx, props)| {
let mut val = use_state(cx, || 0); let mut val = use_state(cx, || 0);
cx.render(rsx! { cx.render(rsx! {

View File

@ -36,7 +36,7 @@ fn main() {
dioxus_desktop::run(APP, (), |c| c.with_edits(edits)); dioxus_desktop::run(APP, (), |c| c.with_edits(edits));
} }
const APP: FC<()> = |cx, _props| { const APP: FC<()> = |(cx, _props)| {
rsx!(cx, div { rsx!(cx, div {
"some app" "some app"
}) })

View File

@ -31,7 +31,7 @@ fn main() {
}); });
} }
static App: FC<()> = |cx, props| { static App: FC<()> = |(cx, props)| {
let state = use_ref(cx, || Calculator::new()); let state = use_ref(cx, || Calculator::new());
let clear_display = state.read().display_value.eq("0"); let clear_display = state.read().display_value.eq("0");
@ -76,7 +76,7 @@ struct CalculatorKeyProps<'a> {
onclick: &'a dyn Fn(MouseEvent), onclick: &'a dyn Fn(MouseEvent),
} }
fn CalculatorKey<'a, 'r>(cx: Context<'a>, props: &'a CalculatorKeyProps) -> DomTree<'a> { fn CalculatorKey<'a>((cx, props): Component<'a, CalculatorKeyProps>) -> DomTree<'a> {
cx.render(rsx! { cx.render(rsx! {
button { button {
class: "calculator-key {props.name}" class: "calculator-key {props.name}"

View File

@ -11,7 +11,7 @@ fn main() {
dioxus::desktop::launch(App, |c| c); dioxus::desktop::launch(App, |c| c);
} }
pub static App: FC<()> = |cx, _| { pub static App: FC<()> = |(cx, _)| {
let state = use_state(cx, PlayerState::new); let state = use_state(cx, PlayerState::new);
let is_playing = state.is_playing(); let is_playing = state.is_playing();

View File

@ -7,7 +7,7 @@ fn main() {
dioxus::desktop::launch(App, |c| c); dioxus::desktop::launch(App, |c| c);
} }
static App: FC<()> = |cx, props| { static App: FC<()> = |(cx, props)| {
let mut count = use_state(cx, || 0); let mut count = use_state(cx, || 0);
cx.render(rsx! { cx.render(rsx! {

View File

@ -49,7 +49,7 @@ const NONE_ELEMENT: Option<()> = None;
use baller::Baller; use baller::Baller;
use dioxus::prelude::*; use dioxus::prelude::*;
pub static Example: FC<()> = |cx, props| { pub static Example: FC<()> = |(cx, props)| {
let formatting = "formatting!"; let formatting = "formatting!";
let formatting_tuple = ("a", "b"); let formatting_tuple = ("a", "b");
let lazy_fmt = format_args!("lazily formatted text"); let lazy_fmt = format_args!("lazily formatted text");
@ -184,7 +184,7 @@ mod baller {
pub struct BallerProps {} pub struct BallerProps {}
/// This component totally balls /// This component totally balls
pub fn Baller<'a>(cx: Context<'a>, props: &BallerProps) -> DomTree<'a> { pub fn Baller(_: Component<BallerProps>) -> DomTree {
todo!() todo!()
} }
} }
@ -195,7 +195,7 @@ pub struct TallerProps {
} }
/// This component is taller than most :) /// This component is taller than most :)
pub fn Taller<'a>(cx: Context<'a>, props: &'a TallerProps) -> DomTree<'a> { pub fn Taller(_: Component<TallerProps>) -> DomTree {
let b = true; let b = true;
todo!() todo!()
} }

View File

@ -9,7 +9,7 @@ fn main() {
println!("{}", ssr::render_vdom(&vdom, |c| c)); println!("{}", ssr::render_vdom(&vdom, |c| c));
} }
static App: FC<()> = |cx, props| { static App: FC<()> = |(cx, props)| {
cx.render(rsx!( cx.render(rsx!(
div { div {
h1 { "Title" } h1 { "Title" }

View File

@ -14,7 +14,7 @@ fn main() {
const STYLE: &str = "body {overflow:hidden;}"; const STYLE: &str = "body {overflow:hidden;}";
pub static App: FC<()> = |cx, props| { pub static App: FC<()> = |(cx, props)| {
cx.render(rsx!( cx.render(rsx!(
div { class: "overflow-hidden" div { class: "overflow-hidden"
style { "{STYLE}" } style { "{STYLE}" }
@ -30,7 +30,7 @@ pub static App: FC<()> = |cx, props| {
)) ))
}; };
pub static Header: FC<()> = |cx, props| { pub static Header: FC<()> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
div { div {
header { class: "text-gray-400 bg-gray-900 body-font" header { class: "text-gray-400 bg-gray-900 body-font"
@ -56,7 +56,7 @@ pub static Header: FC<()> = |cx, props| {
}) })
}; };
pub static Hero: FC<()> = |cx, props| { pub static Hero: FC<()> = |(cx, props)| {
// //
cx.render(rsx! { cx.render(rsx! {
section{ class: "text-gray-400 bg-gray-900 body-font" section{ class: "text-gray-400 bg-gray-900 body-font"
@ -94,7 +94,7 @@ pub static Hero: FC<()> = |cx, props| {
} }
}) })
}; };
pub static Entry: FC<()> = |cx, props| { pub static Entry: FC<()> = |(cx, props)| {
// //
cx.render(rsx! { cx.render(rsx! {
section{ class: "text-gray-400 bg-gray-900 body-font" section{ class: "text-gray-400 bg-gray-900 body-font"
@ -107,7 +107,7 @@ pub static Entry: FC<()> = |cx, props| {
}) })
}; };
pub static StacksIcon: FC<()> = |cx, props| { pub static StacksIcon: FC<()> = |(cx, props)| {
cx.render(rsx!( cx.render(rsx!(
svg { svg {
// xmlns: "http://www.w3.org/2000/svg" // xmlns: "http://www.w3.org/2000/svg"
@ -122,7 +122,7 @@ pub static StacksIcon: FC<()> = |cx, props| {
} }
)) ))
}; };
pub static RightArrowIcon: FC<()> = |cx, props| { pub static RightArrowIcon: FC<()> = |(cx, props)| {
cx.render(rsx!( cx.render(rsx!(
svg { svg {
fill: "none" fill: "none"

View File

@ -22,7 +22,7 @@ pub struct TodoItem {
} }
const STYLE: &str = include_str!("./assets/todomvc.css"); const STYLE: &str = include_str!("./assets/todomvc.css");
const App: FC<()> = |cx, props| { const App: FC<()> = |(cx, props)| {
let draft = use_state(cx, || "".to_string()); let draft = use_state(cx, || "".to_string());
let todos = use_state(cx, || HashMap::<u32, Rc<TodoItem>>::new()); let todos = use_state(cx, || HashMap::<u32, Rc<TodoItem>>::new());
let filter = use_state(cx, || FilterState::All); let filter = use_state(cx, || FilterState::All);
@ -85,7 +85,7 @@ pub struct TodoEntryProps {
todo: Rc<TodoItem>, todo: Rc<TodoItem>,
} }
pub fn TodoEntry<'a>(cx: Context<'a>, props: &TodoEntryProps) -> DomTree<'a> { pub fn TodoEntry((cx, props): Component<TodoEntryProps>) -> DomTree {
let is_editing = use_state(cx, || false); let is_editing = use_state(cx, || false);
let contents = use_state(cx, || String::from("")); let contents = use_state(cx, || String::from(""));
let todo = &props.todo; let todo = &props.todo;

View File

@ -12,7 +12,7 @@ fn main() {
const ENDPOINT: &str = "https://api.openweathermap.org/data/2.5/weather"; const ENDPOINT: &str = "https://api.openweathermap.org/data/2.5/weather";
static App: FC<()> = |cx, props| { static App: FC<()> = |(cx, props)| {
// //
let body = use_suspense( let body = use_suspense(
cx, cx,
@ -38,7 +38,7 @@ static App: FC<()> = |cx, props| {
#[derive(PartialEq, Props)] #[derive(PartialEq, Props)]
struct WeatherProps {} struct WeatherProps {}
static WeatherDisplay: FC<WeatherProps> = |cx, props| { static WeatherDisplay: FC<WeatherProps> = |(cx, props)| {
// //
cx.render(rsx!( cx.render(rsx!(
div { class: "flex items-center justify-center flex-col" div { class: "flex items-center justify-center flex-col"

View File

@ -19,7 +19,7 @@ fn main() {
dioxus::web::launch(App, |c| c); dioxus::web::launch(App, |c| c);
} }
static App: FC<()> = |cx, props| { static App: FC<()> = |(cx, props)| {
let mut rng = SmallRng::from_entropy(); let mut rng = SmallRng::from_entropy();
let rows = (0..1_000).map(|f| { let rows = (0..1_000).map(|f| {
let label = Label::new(&mut rng); let label = Label::new(&mut rng);
@ -45,7 +45,7 @@ struct RowProps {
row_id: usize, row_id: usize,
label: Label, label: Label,
} }
fn Row<'a>(cx: Context<'a>, props: &'a RowProps) -> DomTree<'a> { fn Row((cx, props): Component<RowProps>) -> DomTree {
let [adj, col, noun] = props.label.0; let [adj, col, noun] = props.label.0;
cx.render(rsx! { cx.render(rsx! {
tr { tr {

View File

@ -16,7 +16,7 @@ fn main() {
dioxus::web::launch(App, |c| c); dioxus::web::launch(App, |c| c);
} }
static App: FC<()> = |cx, props| { static App: FC<()> = |(cx, props)| {
let mut count = use_state(cx, || 0); let mut count = use_state(cx, || 0);
cx.render(rsx! { cx.render(rsx! {

View File

@ -12,7 +12,7 @@ https://github.com/rustwasm/gloo
For example, resize observer would function like this: For example, resize observer would function like this:
```rust ```rust
pub static Example: FC<()> = |cx, props|{ pub static Example: FC<()> = |(cx, props)|{
let observer = use_resize_observer(); let observer = use_resize_observer();
cx.render(rsx!( cx.render(rsx!(

View File

@ -153,13 +153,13 @@ Notice that LiveComponent receivers (the client-side interpretation of a LiveCom
The `VNodeTree` type is a very special type that allows VNodes to be created using a pluggable allocator. The html! macro creates something that looks like: The `VNodeTree` type is a very special type that allows VNodes to be created using a pluggable allocator. The html! macro creates something that looks like:
```rust ```rust
pub static Example: FC<()> = |cx, props|{ pub static Example: FC<()> = |(cx, props)|{
html! { <div> "blah" </div> } html! { <div> "blah" </div> }
}; };
// expands to... // expands to...
pub static Example: FC<()> = |cx, props|{ pub static Example: FC<()> = |(cx, props)|{
// This function converts a Fn(allocator) -> DomTree closure to a VNode struct that will later be evaluated. // This function converts a Fn(allocator) -> DomTree closure to a VNode struct that will later be evaluated.
html_macro_to_vnodetree(move |allocator| { html_macro_to_vnodetree(move |allocator| {
let mut node0 = allocator.alloc(VElement::div); let mut node0 = allocator.alloc(VElement::div);
@ -313,7 +313,7 @@ Here's how react does it:
Any "dirty" node causes an entire subtree render. Calling "setState" at the very top will cascade all the way down. This is particularly bad for this component design: Any "dirty" node causes an entire subtree render. Calling "setState" at the very top will cascade all the way down. This is particularly bad for this component design:
```rust ```rust
static APP: FC<()> = |cx, props|{ static APP: FC<()> = |(cx, props)|{
let title = use_context(Title); let title = use_context(Title);
cx.render(html!{ cx.render(html!{
<div> <div>
@ -334,7 +334,7 @@ static APP: FC<()> = |cx, props|{
</div> </div>
}) })
}; };
static HEAVY_LIST: FC<()> = |cx, props|{ static HEAVY_LIST: FC<()> = |(cx, props)|{
cx.render({ cx.render({
{0.100.map(i => <BigElement >)} {0.100.map(i => <BigElement >)}
}) })
@ -378,7 +378,7 @@ struct Props {
} }
static Component: FC<Props> = |cx, props|{ static Component: FC<Props> = |(cx, props)|{
} }
``` ```

View File

@ -30,7 +30,7 @@ pub fn derive_typed_builder(input: proc_macro::TokenStream) -> proc_macro::Token
/// ///
/// ## Complete Reference Guide: /// ## Complete Reference Guide:
/// ``` /// ```
/// const Example: FC<()> = |cx, props|{ /// const Example: FC<()> = |(cx, props)|{
/// let formatting = "formatting!"; /// let formatting = "formatting!";
/// let formatting_tuple = ("a", "b"); /// let formatting_tuple = ("a", "b");
/// let lazy_fmt = format_args!("lazily formatted text"); /// let lazy_fmt = format_args!("lazily formatted text");

View File

@ -72,7 +72,7 @@ impl ToTokens for RsxTemplate {
// // create a lazy tree that accepts a bump allocator // // create a lazy tree that accepts a bump allocator
// let final_tokens = quote! { // let final_tokens = quote! {
// dioxus::prelude::LazyNodes::new(move |cx, props|{ // dioxus::prelude::LazyNodes::new(move |(cx, props)|{
// let bump = &cx.bump(); // let bump = &cx.bump();
// #new_toks // #new_toks

View File

@ -23,7 +23,7 @@ criterion_group!(mbenches, create_rows);
criterion_main!(mbenches); criterion_main!(mbenches);
fn create_rows(c: &mut Criterion) { fn create_rows(c: &mut Criterion) {
static App: FC<()> = |cx, _| { static App: FC<()> = |(cx, _)| {
let mut rng = SmallRng::from_entropy(); let mut rng = SmallRng::from_entropy();
let rows = (0..10_000_usize).map(|f| { let rows = (0..10_000_usize).map(|f| {
let label = Label::new(&mut rng); let label = Label::new(&mut rng);
@ -57,7 +57,7 @@ struct RowProps {
row_id: usize, row_id: usize,
label: Label, label: Label,
} }
fn Row<'a>(cx: Context<'a>, props: &RowProps) -> DomTree<'a> { fn Row((cx, props): Component<RowProps>) -> DomTree {
let [adj, col, noun] = props.label.0; let [adj, col, noun] = props.label.0;
cx.render(rsx! { cx.render(rsx! {
tr { tr {

View File

@ -6,7 +6,7 @@ fn main() {
println!("{}", dom); println!("{}", dom);
} }
pub static EXAMPLE: FC<()> = |cx, _| { pub static EXAMPLE: FC<()> = |(cx, _)| {
let list = (0..10).map(|_f| LazyNodes::new(move |_f| todo!())); let list = (0..10).map(|_f| LazyNodes::new(move |_f| todo!()));
cx.render(LazyNodes::new(move |cx| { cx.render(LazyNodes::new(move |cx| {

View File

@ -5,7 +5,7 @@ fn main() {
dom.rebuild(); dom.rebuild();
} }
const App: FC<()> = |cx, props| { const App: FC<()> = |(cx, props)| {
let id = cx.scope_id(); let id = cx.scope_id();
cx.submit_task(Box::pin(async move { id })); cx.submit_task(Box::pin(async move { id }));

View File

@ -6,7 +6,7 @@ struct SomeContext {
} }
#[allow(unused)] #[allow(unused)]
static Example: FC<()> = |cx, props| { static Example: FC<()> = |(cx, props)| {
todo!() todo!()
// let value = cx.use_context(|c: &SomeContext| c.items.last().unwrap()); // let value = cx.use_context(|c: &SomeContext| c.items.last().unwrap());

View File

@ -1,3 +1,4 @@
use dioxus::component::Component;
use dioxus::events::on::MouseEvent; use dioxus::events::on::MouseEvent;
use dioxus_core as dioxus; use dioxus_core as dioxus;
use dioxus_core::prelude::*; use dioxus_core::prelude::*;
@ -12,7 +13,7 @@ fn main() {
assert!(g.edits.len() > 1); assert!(g.edits.len() > 1);
} }
static App: FC<()> = |cx, props| { static App: FC<()> = |(cx, props)| {
let mut rng = SmallRng::from_entropy(); let mut rng = SmallRng::from_entropy();
let rows = (0..10_000_usize).map(|f| { let rows = (0..10_000_usize).map(|f| {
let label = Label::new(&mut rng); let label = Label::new(&mut rng);
@ -37,7 +38,7 @@ struct RowProps {
row_id: usize, row_id: usize,
label: Label, label: Label,
} }
fn Row<'a>(cx: Context<'a>, props: &'a RowProps) -> DomTree<'a> { fn Row((cx, props): Component<RowProps>) -> DomTree {
let handler = move |evt: MouseEvent| { let handler = move |evt: MouseEvent| {
let g = evt.button; let g = evt.button;
}; };

View File

@ -4,7 +4,7 @@ use dioxus_core::prelude::*;
#[async_std::main] #[async_std::main]
async fn main() { async fn main() {
static App: FC<()> = |cx, props| cx.render(LazyNodes::new(|f| f.text(format_args!("hello")))); static App: FC<()> = |(cx, props)| cx.render(LazyNodes::new(|f| f.text(format_args!("hello"))));
let mut dom = VirtualDom::new(App); let mut dom = VirtualDom::new(App);

View File

@ -7,6 +7,40 @@
use crate::innerlude::{Context, DomTree, LazyNodes, FC}; use crate::innerlude::{Context, DomTree, LazyNodes, FC};
/// A component is a wrapper around a Context and some Props that share a lifetime
///
///
/// # Example
///
/// With memoized state:
/// ```rust
/// struct State {}
///
/// fn Example((cx, props): Component<State>) -> DomTree {
/// // ...
/// }
/// ```
///
/// With borrowed state:
/// ```rust
/// struct State<'a> {
/// name: &'a str
/// }
///
/// fn Example<'a>((cx, props): Component<'a, State>) -> DomTree<'a> {
/// // ...
/// }
/// ```
///
/// With owned state as a closure:
/// ```rust
/// static Example: FC<()> = |(cx, props)| {
/// // ...
/// };
/// ```
///
pub type Component<'a, T> = (Context<'a>, &'a T);
/// Create inline fragments using Component syntax. /// Create inline fragments using Component syntax.
/// ///
/// Fragments capture a series of children without rendering extra nodes. /// Fragments capture a series of children without rendering extra nodes.
@ -29,7 +63,7 @@ use crate::innerlude::{Context, DomTree, LazyNodes, FC};
/// You want to use this free-function when your fragment needs a key and simply returning multiple nodes from rsx! won't cut it. /// You want to use this free-function when your fragment needs a key and simply returning multiple nodes from rsx! won't cut it.
/// ///
#[allow(non_upper_case_globals, non_snake_case)] #[allow(non_upper_case_globals, non_snake_case)]
pub fn Fragment<'a>(cx: Context<'a>, _: &'a ()) -> DomTree<'a> { pub fn Fragment((cx, _): Component<()>) -> DomTree {
cx.render(LazyNodes::new(|f| f.fragment_from_iter(cx.children()))) cx.render(LazyNodes::new(|f| f.fragment_from_iter(cx.children())))
} }

View File

@ -69,7 +69,7 @@ impl<'src> Context<'src> {
/// ## Example /// ## Example
/// ///
/// ```rust /// ```rust
/// const App: FC<()> = |cx, props|{ /// const App: FC<()> = |(cx, props)|{
/// cx.render(rsx!{ /// cx.render(rsx!{
/// CustomCard { /// CustomCard {
/// h1 {} /// h1 {}
@ -78,7 +78,7 @@ impl<'src> Context<'src> {
/// }) /// })
/// } /// }
/// ///
/// const CustomCard: FC<()> = |cx, props|{ /// const CustomCard: FC<()> = |(cx, props)|{
/// cx.render(rsx!{ /// cx.render(rsx!{
/// div { /// div {
/// h1 {"Title card"} /// h1 {"Title card"}
@ -181,12 +181,12 @@ impl<'src> Context<'src> {
/// ``` /// ```
/// struct SharedState(&'static str); /// struct SharedState(&'static str);
/// ///
/// static App: FC<()> = |cx, props|{ /// static App: FC<()> = |(cx, props)|{
/// cx.provide_state(SharedState("world")); /// cx.provide_state(SharedState("world"));
/// rsx!(cx, Child {}) /// rsx!(cx, Child {})
/// } /// }
/// ///
/// static Child: FC<()> = |cx, props|{ /// static Child: FC<()> = |(cx, props)|{
/// let state = cx.consume_state::<SharedState>(); /// let state = cx.consume_state::<SharedState>();
/// rsx!(cx, div { "hello {state.0}" }) /// rsx!(cx, div { "hello {state.0}" })
/// } /// }
@ -221,7 +221,7 @@ impl<'src> Context<'src> {
/// # Example /// # Example
/// ///
/// ```rust /// ```rust
/// static App: FC<()> = |cx, props| { /// static App: FC<()> = |(cx, props)| {
/// todo!(); /// todo!();
/// rsx!(cx, div { "Subtree {id}"}) /// rsx!(cx, div { "Subtree {id}"})
/// }; /// };
@ -238,7 +238,7 @@ impl<'src> Context<'src> {
/// # Example /// # Example
/// ///
/// ```rust /// ```rust
/// static App: FC<()> = |cx, props| { /// static App: FC<()> = |(cx, props)| {
/// let id = cx.get_current_subtree(); /// let id = cx.get_current_subtree();
/// rsx!(cx, div { "Subtree {id}"}) /// rsx!(cx, div { "Subtree {id}"})
/// }; /// };

View File

@ -18,7 +18,7 @@ use std::{any::Any, cell::RefCell, future::Future, ops::Deref, rc::Rc};
/// Returns the handle to the task and the value (if it is ready, else None). /// Returns the handle to the task and the value (if it is ready, else None).
/// ///
/// ``` /// ```
/// static Example: FC<()> = |cx, props| { /// static Example: FC<()> = |(cx, props)| {
/// let (task, value) = use_task(|| async { /// let (task, value) = use_task(|| async {
/// timer::sleep(Duration::from_secs(1)).await; /// timer::sleep(Duration::from_secs(1)).await;
/// "Hello World" /// "Hello World"

View File

@ -57,7 +57,7 @@ pub(crate) mod innerlude {
pub use crate::virtual_dom::*; pub use crate::virtual_dom::*;
pub type DomTree<'a> = Option<VNode<'a>>; pub type DomTree<'a> = Option<VNode<'a>>;
pub type FC<P> = for<'a> fn(Context<'a>, &'a P) -> DomTree<'a>; pub type FC<P> = for<'a> fn(Component<'a, P>) -> DomTree<'a>;
} }
pub use crate::innerlude::{ pub use crate::innerlude::{
@ -67,7 +67,7 @@ pub use crate::innerlude::{
}; };
pub mod prelude { pub mod prelude {
pub use crate::component::{fc_to_builder, Fragment, Properties}; pub use crate::component::{fc_to_builder, Component, Fragment, Properties};
pub use crate::context::Context; pub use crate::context::Context;
pub use crate::hooks::*; pub use crate::hooks::*;
pub use crate::innerlude::{DioxusElement, DomTree, LazyNodes, Mutations, NodeFactory, FC}; pub use crate::innerlude::{DioxusElement, DomTree, LazyNodes, Mutations, NodeFactory, FC};

View File

@ -526,7 +526,7 @@ impl<'a> NodeFactory<'a> {
let caller: &'a mut dyn for<'b> Fn(&'b Scope) -> DomTree<'b> = let caller: &'a mut dyn for<'b> Fn(&'b Scope) -> DomTree<'b> =
bump.alloc(move |scope: &Scope| -> DomTree { bump.alloc(move |scope: &Scope| -> DomTree {
let props: &'_ P = unsafe { &*(raw_props as *const P) }; let props: &'_ P = unsafe { &*(raw_props as *const P) };
let res = component(Context { scope }, props); let res = component((Context { scope }, props));
unsafe { std::mem::transmute(res) } unsafe { std::mem::transmute(res) }
}); });

View File

@ -60,7 +60,7 @@ impl Scope {
/// ///
/// # Example /// # Example
/// ```rust /// ```rust
/// let mut dom = VirtualDom::new(|cx, props|cx.render(rsx!{ div {} })); /// let mut dom = VirtualDom::new(|(cx, props)|cx.render(rsx!{ div {} }));
/// dom.rebuild(); /// dom.rebuild();
/// ///
/// let base = dom.base_scope(); /// let base = dom.base_scope();
@ -82,7 +82,7 @@ impl Scope {
/// # Example /// # Example
/// ///
/// ```rust /// ```rust
/// let mut dom = VirtualDom::new(|cx, props|cx.render(rsx!{ div {} })); /// let mut dom = VirtualDom::new(|(cx, props)|cx.render(rsx!{ div {} }));
/// dom.rebuild(); /// dom.rebuild();
/// ///
/// let base = dom.base_scope(); /// let base = dom.base_scope();
@ -110,7 +110,7 @@ impl Scope {
/// # Example /// # Example
/// ///
/// ```rust /// ```rust
/// let mut dom = VirtualDom::new(|cx, props|cx.render(rsx!{ div {} })); /// let mut dom = VirtualDom::new(|(cx, props)|cx.render(rsx!{ div {} }));
/// dom.rebuild(); /// dom.rebuild();
/// ///
/// let base = dom.base_scope(); /// let base = dom.base_scope();
@ -130,7 +130,7 @@ impl Scope {
/// # Example /// # Example
/// ///
/// ```rust /// ```rust
/// let mut dom = VirtualDom::new(|cx, props|cx.render(rsx!{ div {} })); /// let mut dom = VirtualDom::new(|(cx, props)|cx.render(rsx!{ div {} }));
/// dom.rebuild(); /// dom.rebuild();
/// ///
/// let base = dom.base_scope(); /// let base = dom.base_scope();
@ -148,7 +148,7 @@ impl Scope {
/// # Example /// # Example
/// ///
/// ```rust /// ```rust
/// let mut dom = VirtualDom::new(|cx, props|cx.render(rsx!{ div {} })); /// let mut dom = VirtualDom::new(|(cx, props)|cx.render(rsx!{ div {} }));
/// dom.rebuild(); /// dom.rebuild();
/// let base = dom.base_scope(); /// let base = dom.base_scope();
/// ///

View File

@ -33,7 +33,7 @@ use std::{any::Any, rc::Rc};
/// ///
/// Example /// Example
/// ```rust /// ```rust
/// static App: FC<()> = |cx, props|{ /// static App: FC<()> = |(cx, props)|{
/// cx.render(rsx!{ /// cx.render(rsx!{
/// div { /// div {
/// "Hello World" /// "Hello World"
@ -145,7 +145,7 @@ impl VirtualDom {
// Safety: this callback is only valid for the lifetime of the root props // Safety: this callback is only valid for the lifetime of the root props
let root_caller: Rc<dyn Fn(&Scope) -> DomTree> = Rc::new(move |scope: &Scope| unsafe { let root_caller: Rc<dyn Fn(&Scope) -> DomTree> = Rc::new(move |scope: &Scope| unsafe {
let props = _p.downcast_ref::<P>().unwrap(); let props = _p.downcast_ref::<P>().unwrap();
std::mem::transmute(root(Context { scope }, props)) std::mem::transmute(root((Context { scope }, props)))
}); });
let scheduler = Scheduler::new(sender, receiver); let scheduler = Scheduler::new(sender, receiver);
@ -196,7 +196,7 @@ impl VirtualDom {
/// struct AppProps { /// struct AppProps {
/// route: &'static str /// route: &'static str
/// } /// }
/// static App: FC<AppProps> = |cx, props|cx.render(rsx!{ "route is {cx.route}" }); /// static App: FC<AppProps> = |(cx, props)|cx.render(rsx!{ "route is {cx.route}" });
/// ///
/// let mut dom = VirtualDom::new_with_props(App, AppProps { route: "start" }); /// let mut dom = VirtualDom::new_with_props(App, AppProps { route: "start" });
/// ///
@ -222,7 +222,7 @@ impl VirtualDom {
let root_caller: Box<dyn Fn(&Scope) -> DomTree> = let root_caller: Box<dyn Fn(&Scope) -> DomTree> =
Box::new(move |scope: &Scope| unsafe { Box::new(move |scope: &Scope| unsafe {
let props: &'_ P = &*(props_ptr as *const P); let props: &'_ P = &*(props_ptr as *const P);
std::mem::transmute(root(Context { scope }, props)) std::mem::transmute(root((Context { scope }, props)))
}); });
root_scope.update_scope_dependencies(&root_caller, ScopeChildren(&[])); root_scope.update_scope_dependencies(&root_caller, ScopeChildren(&[]));
@ -246,7 +246,7 @@ impl VirtualDom {
/// ///
/// # Example /// # Example
/// ``` /// ```
/// static App: FC<()> = |cx, props|cx.render(rsx!{ "hello world" }); /// static App: FC<()> = |(cx, props)|cx.render(rsx!{ "hello world" });
/// let mut dom = VirtualDom::new(); /// let mut dom = VirtualDom::new();
/// let edits = dom.rebuild(); /// let edits = dom.rebuild();
/// ///
@ -271,7 +271,7 @@ impl VirtualDom {
/// value: Shared<&'static str>, /// value: Shared<&'static str>,
/// } /// }
/// ///
/// static App: FC<AppProps> = |cx, props|{ /// static App: FC<AppProps> = |(cx, props)|{
/// let val = cx.value.borrow(); /// let val = cx.value.borrow();
/// cx.render(rsx! { div { "{val}" } }) /// cx.render(rsx! { div { "{val}" } })
/// }; /// };
@ -333,7 +333,7 @@ impl VirtualDom {
/// # Example /// # Example
/// ///
/// ```no_run /// ```no_run
/// static App: FC<()> = |cx, props|rsx!(cx, div {"hello"} ); /// static App: FC<()> = |(cx, props)|rsx!(cx, div {"hello"} );
/// let mut dom = VirtualDom::new(App); /// let mut dom = VirtualDom::new(App);
/// loop { /// loop {
/// let deadline = TimeoutFuture::from_ms(16); /// let deadline = TimeoutFuture::from_ms(16);

View File

@ -3,7 +3,7 @@ use dioxus_core as dioxus;
use dioxus_core_macro::*; use dioxus_core_macro::*;
use dioxus_html as dioxus_elements; use dioxus_html as dioxus_elements;
static Parent: FC<()> = |cx, props| { static Parent: FC<()> = |(cx, props)| {
let value = cx.use_hook(|_| String::new(), |f| &*f, |_| {}); let value = cx.use_hook(|_| String::new(), |f| &*f, |_| {});
cx.render(rsx! { cx.render(rsx! {
@ -21,7 +21,7 @@ struct ChildProps<'a> {
name: &'a String, name: &'a String,
} }
fn Child<'a>(cx: Context<'a>, props: &'a ChildProps) -> DomTree<'a> { fn Child<'a>((cx, props): Component<'a, ChildProps>) -> DomTree<'a> {
cx.render(rsx! { cx.render(rsx! {
div { div {
h1 { "it's nested" } h1 { "it's nested" }
@ -35,7 +35,7 @@ struct Grandchild<'a> {
name: &'a String, name: &'a String,
} }
fn Child2<'a>(cx: Context<'a>, props: &Grandchild) -> DomTree<'a> { fn Child2<'a>((cx, props): Component<'a, Grandchild>) -> DomTree<'a> {
cx.render(rsx! { cx.render(rsx! {
div { "Hello {props.name}!" } div { "Hello {props.name}!" }
}) })

View File

@ -19,7 +19,7 @@ fn new_dom<P: 'static + Send>(app: FC<P>, props: P) -> VirtualDom {
#[test] #[test]
fn test_original_diff() { fn test_original_diff() {
static APP: FC<()> = |cx, props| { static APP: FC<()> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
div { div {
div { div {
@ -55,7 +55,7 @@ fn test_original_diff() {
#[test] #[test]
fn create() { fn create() {
static APP: FC<()> = |cx, props| { static APP: FC<()> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
div { div {
div { div {
@ -118,7 +118,7 @@ fn create() {
#[test] #[test]
fn create_list() { fn create_list() {
static APP: FC<()> = |cx, props| { static APP: FC<()> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
{(0..3).map(|f| rsx!{ div { {(0..3).map(|f| rsx!{ div {
"hello" "hello"
@ -167,7 +167,7 @@ fn create_list() {
#[test] #[test]
fn create_simple() { fn create_simple() {
static APP: FC<()> = |cx, props| { static APP: FC<()> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
div {} div {}
div {} div {}
@ -205,7 +205,7 @@ fn create_simple() {
} }
#[test] #[test]
fn create_components() { fn create_components() {
static App: FC<()> = |cx, props| { static App: FC<()> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
Child { "abc1" } Child { "abc1" }
Child { "abc2" } Child { "abc2" }
@ -213,7 +213,7 @@ fn create_components() {
}) })
}; };
static Child: FC<()> = |cx, props| { static Child: FC<()> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
h1 {} h1 {}
div { {cx.children()} } div { {cx.children()} }
@ -266,7 +266,7 @@ fn create_components() {
} }
#[test] #[test]
fn anchors() { fn anchors() {
static App: FC<()> = |cx, props| { static App: FC<()> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
{true.then(|| rsx!{ div { "hello" } })} {true.then(|| rsx!{ div { "hello" } })}
{false.then(|| rsx!{ div { "goodbye" } })} {false.then(|| rsx!{ div { "goodbye" } })}
@ -295,13 +295,13 @@ fn anchors() {
#[test] #[test]
fn suspended() { fn suspended() {
static App: FC<()> = |cx, props| { static App: FC<()> = |(cx, props)| {
let val = use_suspense( let val = use_suspense(
cx, cx,
|| async { || async {
// //
}, },
|cx, _| cx.render(rsx! { "hi "}), |cx, p| cx.render(rsx! { "hi "}),
); );
cx.render(rsx! { {val} }) cx.render(rsx! { {val} })
}; };

View File

@ -16,7 +16,7 @@ const IS_LOGGING_ENABLED: bool = true;
#[test] #[test]
fn please_work() { fn please_work() {
static App: FC<()> = |cx, props| { static App: FC<()> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
div { div {
hidden: "true" hidden: "true"
@ -30,7 +30,7 @@ fn please_work() {
}) })
}; };
static Child: FC<()> = |cx, props| { static Child: FC<()> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
div { "child" } div { "child" }
}) })

View File

@ -8,7 +8,7 @@ use dioxus_html as dioxus_elements;
#[async_std::test] #[async_std::test]
async fn event_queue_works() { async fn event_queue_works() {
static App: FC<()> = |cx, props| { static App: FC<()> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
div { "hello world" } div { "hello world" }
}) })

View File

@ -10,7 +10,7 @@ type Shared<T> = Rc<RefCell<T>>;
#[test] #[test]
fn sample_refs() { fn sample_refs() {
// static App: FC<()> = |cx, props|{ // static App: FC<()> = |(cx, props)|{
// let div_ref = use_node_ref::<MyRef, _>(cx); // let div_ref = use_node_ref::<MyRef, _>(cx);
// cx.render(rsx! { // cx.render(rsx! {

View File

@ -20,7 +20,7 @@ fn manual_diffing() {
value: Shared<&'static str>, value: Shared<&'static str>,
} }
static App: FC<AppProps> = |cx, props| { static App: FC<AppProps> = |(cx, props)| {
let val = props.value.lock().unwrap(); let val = props.value.lock().unwrap();
cx.render(rsx! { div { "{val}" } }) cx.render(rsx! { div { "{val}" } })
}; };

View File

@ -17,12 +17,12 @@ fn new_dom() -> TestDom {
fn shared_state_test() { fn shared_state_test() {
struct MySharedState(&'static str); struct MySharedState(&'static str);
static App: FC<()> = |cx, props| { static App: FC<()> = |(cx, props)| {
cx.provide_state(MySharedState("world!")); cx.provide_state(MySharedState("world!"));
rsx!(cx, Child {}) rsx!(cx, Child {})
}; };
static Child: FC<()> = |cx, props| { static Child: FC<()> = |(cx, props)| {
let shared = cx.consume_state::<MySharedState>()?; let shared = cx.consume_state::<MySharedState>()?;
rsx!(cx, "Hello, {shared.0}") rsx!(cx, "Hello, {shared.0}")
}; };

View File

@ -15,7 +15,7 @@ use dioxus_html as dioxus_elements;
#[test] #[test]
fn app_runs() { fn app_runs() {
static App: FC<()> = |cx, props| { static App: FC<()> = |(cx, props)| {
// //
cx.render(rsx!( div{"hello"} )) cx.render(rsx!( div{"hello"} ))
}; };
@ -26,7 +26,7 @@ fn app_runs() {
#[test] #[test]
fn fragments_work() { fn fragments_work() {
static App: FC<()> = |cx, props| { static App: FC<()> = |(cx, props)| {
cx.render(rsx!( cx.render(rsx!(
div{"hello"} div{"hello"}
div{"goodbye"} div{"goodbye"}
@ -40,7 +40,7 @@ fn fragments_work() {
#[test] #[test]
fn lists_work() { fn lists_work() {
static App: FC<()> = |cx, props| { static App: FC<()> = |(cx, props)| {
cx.render(rsx!( cx.render(rsx!(
h1 {"hello"} h1 {"hello"}
{(0..6).map(|f| rsx!(span{ "{f}" }))} {(0..6).map(|f| rsx!(span{ "{f}" }))}
@ -53,7 +53,7 @@ fn lists_work() {
#[test] #[test]
fn conditional_rendering() { fn conditional_rendering() {
static App: FC<()> = |cx, props| { static App: FC<()> = |(cx, props)| {
cx.render(rsx!( cx.render(rsx!(
h1 {"hello"} h1 {"hello"}
{true.then(|| rsx!(span{ "a" }))} {true.then(|| rsx!(span{ "a" }))}
@ -70,13 +70,13 @@ fn conditional_rendering() {
#[test] #[test]
fn child_components() { fn child_components() {
static App: FC<()> = |cx, props| { static App: FC<()> = |(cx, props)| {
cx.render(rsx!( cx.render(rsx!(
{true.then(|| rsx!(Child { }))} {true.then(|| rsx!(Child { }))}
{false.then(|| rsx!(Child { }))} {false.then(|| rsx!(Child { }))}
)) ))
}; };
static Child: FC<()> = |cx, props| { static Child: FC<()> = |(cx, props)| {
cx.render(rsx!( cx.render(rsx!(
h1 {"hello"} h1 {"hello"}
h1 {"goodbye"} h1 {"goodbye"}
@ -89,7 +89,7 @@ fn child_components() {
#[test] #[test]
fn suspended_works() { fn suspended_works() {
static App: FC<()> = |cx, props| { static App: FC<()> = |(cx, props)| {
let title = use_suspense(cx, || async { "bob" }, |cx, f| cx.render(rsx! { "{f}"})); let title = use_suspense(cx, || async { "bob" }, |cx, f| cx.render(rsx! { "{f}"}));
cx.render(rsx!("hello" { title })) cx.render(rsx!("hello" { title }))
}; };

View File

@ -7,7 +7,7 @@ fn main() {
dioxus::desktop::launch(App, |c| c) dioxus::desktop::launch(App, |c| c)
} }
static App: FC<()> = |cx, props| { static App: FC<()> = |(cx, props)| {
let (count, set_count) = use_state(cx, || 0); let (count, set_count) = use_state(cx, || 0);
cx.render(rsx!( cx.render(rsx!(
@ -34,7 +34,7 @@ Window management, system trays, notifications, and other desktop-related functi
Managing windows is done by simply rendering content into a `WebviewWindow` component. Managing windows is done by simply rendering content into a `WebviewWindow` component.
```rust ```rust
static App: FC<()> = |cx, props| { static App: FC<()> = |(cx, props)| {
rsx!(cx, WebviewWindow { "hello world" } ) rsx!(cx, WebviewWindow { "hello world" } )
} }
``` ```
@ -46,7 +46,7 @@ Notifications also use a declarative approach. Sending a notification has never
The api has been somewhat modeled after https://github.com/mikaelbr/node-notifier The api has been somewhat modeled after https://github.com/mikaelbr/node-notifier
```rust ```rust
static Notifications: FC<()> = |cx, props| { static Notifications: FC<()> = |(cx, props)| {
cx.render(rsx!( cx.render(rsx!(
Notification { Notification {
title: "title" title: "title"
@ -78,7 +78,7 @@ static Notifications: FC<()> = |cx, props| {
Dioxus Desktop supports app trays, which can be built with native menu groups or with a custom window. Dioxus Desktop supports app trays, which can be built with native menu groups or with a custom window.
```rust ```rust
static Tray: FC<()> = |cx, props| { static Tray: FC<()> = |(cx, props)| {
cx.render(rsx!( cx.render(rsx!(
GlobalTray { GlobalTray {
MenuGroup { MenuGroup {
@ -90,7 +90,7 @@ static Tray: FC<()> = |cx, props| {
}; };
// using a builder // using a builder
static Tray: FC<()> = |cx, props| { static Tray: FC<()> = |(cx, props)| {
let menu = MenuGroup::builder(cx) let menu = MenuGroup::builder(cx)
.with_items([ .with_items([
MenuGroupItem::builder() MenuGroupItem::builder()
@ -107,7 +107,7 @@ static Tray: FC<()> = |cx, props| {
} }
// or with a custom window // or with a custom window
static Tray: FC<()> = |cx, props| { static Tray: FC<()> = |(cx, props)| {
rsx!(cx, GlobalTray { div { "custom buttons here" } }) rsx!(cx, GlobalTray { div { "custom buttons here" } })
}; };
``` ```
@ -116,7 +116,7 @@ static Tray: FC<()> = |cx, props| {
Declaring menus is convenient and cross-platform. Declaring menus is convenient and cross-platform.
```rust ```rust
static Menu: FC<()> = |cx, props| { static Menu: FC<()> = |(cx, props)| {
cx.render(rsx!( cx.render(rsx!(
MenuBarMajorItem { title: "File" MenuBarMajorItem { title: "File"
MenuGroup { MenuGroup {

View File

@ -21,7 +21,7 @@ pub struct Client {
pub description: String, pub description: String,
} }
static App: FC<()> = |cx, _| { static App: FC<()> = |(cx, _)| {
let scene = use_state(cx, || Scene::ClientsList); let scene = use_state(cx, || Scene::ClientsList);
let clients = use_ref(cx, || vec![] as Vec<Client>); let clients = use_ref(cx, || vec![] as Vec<Client>);

View File

@ -8,7 +8,7 @@ fn main() {
dioxus_desktop::launch(App, |c| c); dioxus_desktop::launch(App, |c| c);
} }
static App: FC<()> = |cx, props| { static App: FC<()> = |(cx, props)| {
cx.render(rsx!( cx.render(rsx!(
div { div {
"hello world!" "hello world!"

View File

@ -1,5 +1,6 @@
use std::cell::RefCell; use std::cell::RefCell;
use dioxus::prelude::Component;
use dioxus_core as dioxus; use dioxus_core as dioxus;
use dioxus_core::{Context, DomTree, LazyNodes, NodeFactory, Properties}; use dioxus_core::{Context, DomTree, LazyNodes, NodeFactory, Properties};
use dioxus_core_macro::Props; use dioxus_core_macro::Props;
@ -53,7 +54,7 @@ pub struct WebviewWindowProps<'a> {
/// ///
/// ///
/// ///
pub fn WebviewWindow<'a>(cx: Context<'a>, props: &'a WebviewWindowProps) -> DomTree<'a> { pub fn WebviewWindow<'a>((cx, props): Component<'a, WebviewWindowProps>) -> DomTree<'a> {
let dtcx = cx.consume_state::<RefCell<DesktopContext>>()?; let dtcx = cx.consume_state::<RefCell<DesktopContext>>()?;
cx.use_hook( cx.use_hook(
@ -89,7 +90,7 @@ fn syntax_works() {
use dioxus_hooks::*; use dioxus_hooks::*;
use dioxus_html as dioxus_elements; use dioxus_html as dioxus_elements;
static App: FC<()> = |cx, props| { static App: FC<()> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
// left window // left window
WebviewWindow { WebviewWindow {

View File

@ -10,7 +10,7 @@ fn main() {}
// Remvoe, // Remvoe,
// } // }
// static Component: FC<()> = |cx, props|{ // static Component: FC<()> = |(cx, props)|{
// let (tasks, dispatch) = use_reducer( // let (tasks, dispatch) = use_reducer(
// cx, // cx,
// || CompState { tasks: Vec::new() }, // || CompState { tasks: Vec::new() },

View File

@ -36,7 +36,7 @@ uses the same memoization on top of the use_context API.
Here's a fully-functional todo app using the use_map API: Here's a fully-functional todo app using the use_map API:
```rust ```rust
static TodoList: FC<()> = |cx, props|{ static TodoList: FC<()> = |(cx, props)|{
let todos = use_map(cx, || HashMap::new()); let todos = use_map(cx, || HashMap::new());
let input = use_ref(|| None); let input = use_ref(|| None);

View File

@ -35,7 +35,7 @@ use std::{
/// ///
/// Usage: /// Usage:
/// ```ignore /// ```ignore
/// const Example: FC<()> = |cx, props|{ /// const Example: FC<()> = |(cx, props)|{
/// let counter = use_state(cx, || 0); /// let counter = use_state(cx, || 0);
/// let increment = |_| counter += 1; /// let increment = |_| counter += 1;
/// let decrement = |_| counter += 1; /// let decrement = |_| counter += 1;

View File

@ -5,7 +5,7 @@ Render a Dioxus VirtualDOM to a string.
```rust ```rust
// Our app: // Our app:
const App: FC<()> = |cx, props| rsx!(cx, div {"hello world!"}); const App: FC<()> = |(cx, props)| rsx!(cx, div {"hello world!"});
// Build the virtualdom from our app // Build the virtualdom from our app
let mut vdom = VirtualDOM::new(App); let mut vdom = VirtualDOM::new(App);

View File

@ -12,7 +12,7 @@ fn main() {
) )
} }
pub static App: FC<()> = |cx, props| { pub static App: FC<()> = |(cx, props)| {
cx.render(rsx!( cx.render(rsx!(
div { div {
class: "overflow-hidden" class: "overflow-hidden"

View File

@ -42,7 +42,7 @@ fn main() {}
// initial_name: String, // initial_name: String,
// } // }
// static Example: FC<ExampleProps> = |cx, props| { // static Example: FC<ExampleProps> = |(cx, props)| {
// let dispaly_name = use_state(cx, move || props.initial_name.clone()); // let dispaly_name = use_state(cx, move || props.initial_name.clone());
// cx.render(rsx! { // cx.render(rsx! {

View File

@ -24,7 +24,7 @@ fn main() {
.unwrap(); .unwrap();
} }
pub static App: FC<()> = |cx, props| { pub static App: FC<()> = |(cx, props)| {
cx.render(rsx!( cx.render(rsx!(
div { class: "overflow-hidden" div { class: "overflow-hidden"
link { href:"https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel:"stylesheet" } link { href:"https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel:"stylesheet" }
@ -39,7 +39,7 @@ pub static App: FC<()> = |cx, props| {
)) ))
}; };
pub static Header: FC<()> = |cx, props| { pub static Header: FC<()> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
div { div {
header { class: "text-gray-400 bg-gray-900 body-font" header { class: "text-gray-400 bg-gray-900 body-font"
@ -65,7 +65,7 @@ pub static Header: FC<()> = |cx, props| {
}) })
}; };
pub static Hero: FC<()> = |cx, props| { pub static Hero: FC<()> = |(cx, props)| {
// //
cx.render(rsx! { cx.render(rsx! {
section{ class: "text-gray-400 bg-gray-900 body-font" section{ class: "text-gray-400 bg-gray-900 body-font"
@ -103,7 +103,7 @@ pub static Hero: FC<()> = |cx, props| {
} }
}) })
}; };
pub static Entry: FC<()> = |cx, props| { pub static Entry: FC<()> = |(cx, props)| {
// //
cx.render(rsx! { cx.render(rsx! {
section{ class: "text-gray-400 bg-gray-900 body-font" section{ class: "text-gray-400 bg-gray-900 body-font"
@ -116,7 +116,7 @@ pub static Entry: FC<()> = |cx, props| {
}) })
}; };
pub static StacksIcon: FC<()> = |cx, props| { pub static StacksIcon: FC<()> = |(cx, props)| {
cx.render(rsx!( cx.render(rsx!(
svg { svg {
// xmlns: "http://www.w3.org/2000/svg" // xmlns: "http://www.w3.org/2000/svg"
@ -131,7 +131,7 @@ pub static StacksIcon: FC<()> = |cx, props| {
} }
)) ))
}; };
pub static RightArrowIcon: FC<()> = |cx, props| { pub static RightArrowIcon: FC<()> = |(cx, props)| {
cx.render(rsx!( cx.render(rsx!(
svg { svg {
fill: "none" fill: "none"

View File

@ -44,7 +44,7 @@ pub fn render_vdom_scope(vdom: &VirtualDom, scope: ScopeId) -> Option<String> {
/// ///
/// ## Example /// ## Example
/// ```ignore /// ```ignore
/// static App: FC<()> = |cx, props|cx.render(rsx!(div { "hello world" })); /// static App: FC<()> = |(cx, props)|cx.render(rsx!(div { "hello world" }));
/// let mut vdom = VirtualDom::new(App); /// let mut vdom = VirtualDom::new(App);
/// vdom.rebuild(); /// vdom.rebuild();
/// ///
@ -243,13 +243,13 @@ mod tests {
use dioxus_core_macro::*; use dioxus_core_macro::*;
use dioxus_html as dioxus_elements; use dioxus_html as dioxus_elements;
static SIMPLE_APP: FC<()> = |cx, props| { static SIMPLE_APP: FC<()> = |(cx, props)| {
cx.render(rsx!(div { cx.render(rsx!(div {
"hello world!" "hello world!"
})) }))
}; };
static SLIGHTLY_MORE_COMPLEX: FC<()> = |cx, props| { static SLIGHTLY_MORE_COMPLEX: FC<()> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
div { div {
title: "About W3Schools" title: "About W3Schools"
@ -268,14 +268,14 @@ mod tests {
}) })
}; };
static NESTED_APP: FC<()> = |cx, props| { static NESTED_APP: FC<()> = |(cx, props)| {
cx.render(rsx!( cx.render(rsx!(
div { div {
SIMPLE_APP {} SIMPLE_APP {}
} }
)) ))
}; };
static FRAGMENT_APP: FC<()> = |cx, props| { static FRAGMENT_APP: FC<()> = |(cx, props)| {
cx.render(rsx!( cx.render(rsx!(
div { "f1" } div { "f1" }
div { "f2" } div { "f2" }
@ -331,7 +331,7 @@ mod tests {
#[test] #[test]
fn styles() { fn styles() {
static STLYE_APP: FC<()> = |cx, props| { static STLYE_APP: FC<()> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
div { style: { color: "blue", font_size: "46px" } } div { style: { color: "blue", font_size: "46px" } }
}) })

View File

@ -16,7 +16,7 @@ struct DogApi {
message: String, message: String,
} }
static APP: FC<()> = |cx, _props| { static APP: FC<()> = |(cx, _props)| {
let state = use_state(cx, || 0); let state = use_state(cx, || 0);
const ENDPOINT: &str = "https://dog.ceo/api/breeds/image/random/"; const ENDPOINT: &str = "https://dog.ceo/api/breeds/image/random/";

View File

@ -14,7 +14,7 @@ fn main() {
dioxus_web::launch(APP, |c| c) dioxus_web::launch(APP, |c| c)
} }
static APP: FC<()> = |cx, _| { static APP: FC<()> = |(cx, _)| {
let mut count = use_state(cx, || 3); let mut count = use_state(cx, || 3);
let content = use_state(cx, || String::from("h1")); let content = use_state(cx, || String::from("h1"));
let text_content = use_state(cx, || String::from("Hello, world!")); let text_content = use_state(cx, || String::from("Hello, world!"));
@ -86,4 +86,4 @@ fn render_list(cx: Context, count: usize) -> DomTree {
rsx!(cx, ul { {items} }) rsx!(cx, ul { {items} })
} }
static CHILD: FC<()> = |cx, _| rsx!(cx, div {"hello child"}); static CHILD: FC<()> = |(cx, _)| rsx!(cx, div {"hello child"});

View File

@ -24,7 +24,7 @@ fn main() {
dioxus_web::launch(App, |c| c) dioxus_web::launch(App, |c| c)
} }
static App: FC<()> = |cx, props| { static App: FC<()> = |(cx, props)| {
let mut state = use_state(cx, || 0); let mut state = use_state(cx, || 0);
cx.render(rsx! { cx.render(rsx! {
div { div {

View File

@ -23,7 +23,7 @@ fn main() {
// dioxus::web::launch(App, |c| c); // dioxus::web::launch(App, |c| c);
} }
static App: FC<()> = |cx, props| { static App: FC<()> = |(cx, props)| {
dbg!("rednering parent"); dbg!("rednering parent");
cx.render(rsx! { cx.render(rsx! {
div { div {
@ -40,7 +40,7 @@ static App: FC<()> = |cx, props| {
}) })
}; };
static But: FC<()> = |cx, props| { static But: FC<()> = |(cx, props)| {
let mut count = use_state(cx, || 0); let mut count = use_state(cx, || 0);
// let d = Dropper { name: "asd" }; // let d = Dropper { name: "asd" };

View File

@ -28,7 +28,7 @@ pub struct Client {
pub description: String, pub description: String,
} }
static App: FC<()> = |cx, _| { static App: FC<()> = |(cx, _)| {
let scene = use_state(cx, || Scene::ClientsList); let scene = use_state(cx, || Scene::ClientsList);
let clients = use_ref(cx, || vec![] as Vec<Client>); let clients = use_ref(cx, || vec![] as Vec<Client>);

View File

@ -24,7 +24,7 @@ fn main() {
dioxus_web::launch(App, |c| c) dioxus_web::launch(App, |c| c)
} }
pub static App: FC<()> = |cx, props| { pub static App: FC<()> = |(cx, props)| {
cx.render(rsx!( cx.render(rsx!(
div { class: "overflow-hidden" div { class: "overflow-hidden"
link { href:"https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel:"stylesheet" } link { href:"https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel:"stylesheet" }
@ -39,7 +39,7 @@ pub static App: FC<()> = |cx, props| {
)) ))
}; };
pub static Header: FC<()> = |cx, props| { pub static Header: FC<()> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
div { div {
header { class: "text-gray-400 bg-gray-900 body-font" header { class: "text-gray-400 bg-gray-900 body-font"
@ -65,7 +65,7 @@ pub static Header: FC<()> = |cx, props| {
}) })
}; };
pub static Hero: FC<()> = |cx, props| { pub static Hero: FC<()> = |(cx, props)| {
// //
cx.render(rsx! { cx.render(rsx! {
section{ class: "text-gray-400 bg-gray-900 body-font" section{ class: "text-gray-400 bg-gray-900 body-font"
@ -103,7 +103,7 @@ pub static Hero: FC<()> = |cx, props| {
} }
}) })
}; };
pub static Entry: FC<()> = |cx, props| { pub static Entry: FC<()> = |(cx, props)| {
// //
cx.render(rsx! { cx.render(rsx! {
section{ class: "text-gray-400 bg-gray-900 body-font" section{ class: "text-gray-400 bg-gray-900 body-font"
@ -116,7 +116,7 @@ pub static Entry: FC<()> = |cx, props| {
}) })
}; };
pub static StacksIcon: FC<()> = |cx, props| { pub static StacksIcon: FC<()> = |(cx, props)| {
cx.render(rsx!( cx.render(rsx!(
svg { svg {
// xmlns: "http://www.w3.org/2000/svg" // xmlns: "http://www.w3.org/2000/svg"
@ -131,7 +131,7 @@ pub static StacksIcon: FC<()> = |cx, props| {
} }
)) ))
}; };
pub static RightArrowIcon: FC<()> = |cx, props| { pub static RightArrowIcon: FC<()> = |(cx, props)| {
cx.render(rsx!( cx.render(rsx!(
svg { svg {
fill: "none" fill: "none"

View File

@ -86,7 +86,7 @@ mod ric_raf;
/// dioxus_web::launch(App, |c| c); /// dioxus_web::launch(App, |c| c);
/// } /// }
/// ///
/// static App: FC<()> = |cx, props| { /// static App: FC<()> = |(cx, props)| {
/// rsx!(cx, div {"hello world"}) /// rsx!(cx, div {"hello world"})
/// } /// }
/// ``` /// ```
@ -110,7 +110,7 @@ pub fn launch(root_component: FC<()>, configuration: impl FnOnce(WebConfig) -> W
/// name: String /// name: String
/// } /// }
/// ///
/// static App: FC<RootProps> = |cx, props| { /// static App: FC<RootProps> = |(cx, props)| {
/// rsx!(cx, div {"hello {props.name}"}) /// rsx!(cx, div {"hello {props.name}"})
/// } /// }
/// ``` /// ```

View File

@ -32,7 +32,7 @@ use dioxus::prelude::*;
struct NoKeysProps { struct NoKeysProps {
data: std::collections::HashMap<u32, String>, data: std::collections::HashMap<u32, String>,
} }
static AntipatternNoKeys: FC<NoKeysProps> = |cx, props| { static AntipatternNoKeys: FC<NoKeysProps> = |(cx, props)| {
// WRONG: Make sure to add keys! // WRONG: Make sure to add keys!
rsx!(cx, ul { rsx!(cx, ul {
{props.data.iter().map(|(k, v)| rsx!(li { "List item: {v}" }))} {props.data.iter().map(|(k, v)| rsx!(li { "List item: {v}" }))}
@ -54,7 +54,7 @@ static AntipatternNoKeys: FC<NoKeysProps> = |cx, props| {
/// ///
/// Only Component and Fragment nodes are susceptible to this issue. Dioxus mitigates this with components by providing /// 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. /// an API for registering shared state without the ContextProvider pattern.
static AntipatternNestedFragments: FC<()> = |cx, props| { static AntipatternNestedFragments: FC<()> = |(cx, props)| {
// Try to avoid heavily nesting fragments // Try to avoid heavily nesting fragments
rsx!(cx, rsx!(cx,
Fragment { Fragment {
@ -82,7 +82,7 @@ static AntipatternNestedFragments: FC<()> = |cx, props| {
/// However, calling set_state will *not* update the current version of state in the component. This should be easy to /// However, calling set_state will *not* update the current version of state in the component. This should be easy to
/// recognize from the function signature, but Dioxus will not update the "live" version of state. Calling `set_state` /// recognize from the function signature, but Dioxus will not update the "live" version of state. Calling `set_state`
/// merely places a new value in the queue and schedules the component for a future update. /// merely places a new value in the queue and schedules the component for a future update.
static AntipaternRelyingOnSetState: FC<()> = |cx, props| { static AntipaternRelyingOnSetState: FC<()> = |(cx, props)| {
let (state, set_state) = use_state(cx, || "Hello world").classic(); let (state, set_state) = use_state(cx, || "Hello world").classic();
set_state("New state"); set_state("New state");
// This will return false! `state` will *still* be "Hello world" // This will return false! `state` will *still* be "Hello world"
@ -99,7 +99,7 @@ static AntipaternRelyingOnSetState: FC<()> = |cx, props| {
/// - All components must start with an uppercase character /// - All components must start with an uppercase character
/// ///
/// IE: the following component will be rejected when attempted to be used in the rsx! macro /// IE: the following component will be rejected when attempted to be used in the rsx! macro
static antipattern_component: FC<()> = |cx, props| todo!(); static antipattern_component: FC<()> = |(cx, props)| todo!();
/// Antipattern: Misusing hooks /// Antipattern: Misusing hooks
/// --------------------------- /// ---------------------------
@ -120,7 +120,7 @@ static antipattern_component: FC<()> = |cx, props| todo!();
struct MisuedHooksProps { struct MisuedHooksProps {
should_render_state: bool, should_render_state: bool,
} }
static AntipatternMisusedHooks: FC<MisuedHooksProps> = |cx, props| { static AntipatternMisusedHooks: FC<MisuedHooksProps> = |(cx, props)| {
if props.should_render_state { if props.should_render_state {
// do not place a hook in the conditional! // do not place a hook in the conditional!
// prefer to move it out of the conditional // prefer to move it out of the conditional
@ -153,7 +153,7 @@ static AntipatternMisusedHooks: FC<MisuedHooksProps> = |cx, props| {
/// } /// }
/// } /// }
/// }) /// })
static _example: FC<()> = |cx, props| todo!(); static _example: FC<()> = |(cx, props)| todo!();
/// Antipattern: publishing components and hooks with all features enabled /// Antipattern: publishing components and hooks with all features enabled
/// ---------------------------------------------------------------------- /// ----------------------------------------------------------------------
@ -171,9 +171,9 @@ static _example: FC<()> = |cx, props| todo!();
/// ///
/// This will only include the `core` dioxus crate which is relatively slim and fast to compile and avoids target-specific /// This will only include the `core` dioxus crate which is relatively slim and fast to compile and avoids target-specific
/// libraries. /// libraries.
static __example: FC<()> = |cx, props| todo!(); static __example: FC<()> = |(cx, props)| todo!();
pub static Example: FC<()> = |cx, props| { pub static Example: FC<()> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
AntipatternNoKeys { data: std::collections::HashMap::new() } AntipatternNoKeys { data: std::collections::HashMap::new() }
AntipatternNestedFragments {} AntipatternNestedFragments {}

View File

@ -9,7 +9,7 @@
use dioxus::prelude::*; use dioxus::prelude::*;
pub static Example: FC<()> = |cx, props| { pub static Example: FC<()> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
div { div {
Greeting { Greeting {
@ -25,7 +25,7 @@ struct GreetingProps {
name: &'static str, name: &'static str,
} }
static Greeting: FC<GreetingProps> = |cx, props| { static Greeting: FC<GreetingProps> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
div { div {
h1 { "Hello, {props.name}!" } h1 { "Hello, {props.name}!" }

View File

@ -18,7 +18,7 @@
use dioxus::prelude::*; use dioxus::prelude::*;
pub static Example: FC<()> = |cx, props| { pub static Example: FC<()> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
div { div {
Banner { Banner {
@ -31,7 +31,7 @@ pub static Example: FC<()> = |cx, props| {
}) })
}; };
pub static Banner: FC<()> = |cx, props| { pub static Banner: FC<()> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
div { div {
h1 { "This is a great banner!" } h1 { "This is a great banner!" }

View File

@ -16,7 +16,7 @@ use dioxus::prelude::*;
pub struct MyProps { pub struct MyProps {
should_show: bool, should_show: bool,
} }
pub static Example0: FC<MyProps> = |cx, props| { pub static Example0: FC<MyProps> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
div { div {
{props.should_show.then(|| rsx!{ {props.should_show.then(|| rsx!{
@ -39,7 +39,7 @@ pub static Example0: FC<MyProps> = |cx, props| {
pub struct MyProps1 { pub struct MyProps1 {
should_show: bool, should_show: bool,
} }
pub static Example1: FC<MyProps1> = |cx, props| { pub static Example1: FC<MyProps1> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
div { div {
// With matching // With matching
@ -77,7 +77,7 @@ pub enum Color {
pub struct MyProps2 { pub struct MyProps2 {
color: Color, color: Color,
} }
pub static Example2: FC<MyProps2> = |cx, props| { pub static Example2: FC<MyProps2> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
div { div {
{match props.color { {match props.color {
@ -89,7 +89,7 @@ pub static Example2: FC<MyProps2> = |cx, props| {
}) })
}; };
pub static Example: FC<()> = |cx, props| { pub static Example: FC<()> = |(cx, props)| {
let should_show = use_state(cx, || false); let should_show = use_state(cx, || false);
let mut color_index = use_state(cx, || 0); let mut color_index = use_state(cx, || 0);
let color = match *color_index % 2 { let color = match *color_index % 2 {

View File

@ -1,7 +1,7 @@
use dioxus::prelude::*; use dioxus::prelude::*;
fn main() {} fn main() {}
pub static Example: FC<()> = |cx, props| { pub static Example: FC<()> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
div { div {
@ -10,7 +10,7 @@ pub static Example: FC<()> = |cx, props| {
}; };
// A controlled component: // A controlled component:
static ControlledSelect: FC<()> = |cx, props| { static ControlledSelect: FC<()> = |(cx, props)| {
let value = use_state(cx, || String::from("Grapefruit")); let value = use_state(cx, || String::from("Grapefruit"));
cx.render(rsx! { cx.render(rsx! {
select { value: "{value}", onchange: move |evt| value.set(evt.value()), select { value: "{value}", onchange: move |evt| value.set(evt.value()),
@ -23,7 +23,7 @@ static ControlledSelect: FC<()> = |cx, props| {
}; };
// TODO - how do uncontrolled things work? // TODO - how do uncontrolled things work?
static UncontrolledSelect: FC<()> = |cx, props| { static UncontrolledSelect: FC<()> = |(cx, props)| {
let value = use_state(cx, || String::new()); let value = use_state(cx, || String::new());
cx.render(rsx! { cx.render(rsx! {

View File

@ -11,7 +11,7 @@
use dioxus::prelude::*; use dioxus::prelude::*;
pub static Example: FC<()> = |cx, props| { pub static Example: FC<()> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
div { div {
custom_element { custom_element {

View File

@ -5,4 +5,4 @@
use dioxus::prelude::*; use dioxus::prelude::*;
pub static Example: FC<()> = |cx, props| cx.render(rsx! { Fragment {} }); pub static Example: FC<()> = |(cx, props)| cx.render(rsx! { Fragment {} });

View File

@ -23,14 +23,14 @@ fn main() {}
/// This is one way to go about error handling (just toss things away with unwrap). /// This is one way to go about error handling (just toss things away with unwrap).
/// However, if you get it wrong, the whole app will crash. /// However, if you get it wrong, the whole app will crash.
/// This is pretty flimsy. /// This is pretty flimsy.
static App: FC<()> = |cx, props| { static App: FC<()> = |(cx, props)| {
let data = get_data().unwrap(); let data = get_data().unwrap();
cx.render(rsx!( div { "{data}" } )) cx.render(rsx!( div { "{data}" } ))
}; };
/// This is a pretty verbose way of error handling /// This is a pretty verbose way of error handling
/// However, it's still pretty good since we don't panic, just fail to render anything /// However, it's still pretty good since we don't panic, just fail to render anything
static App1: FC<()> = |cx, props| { static App1: FC<()> = |(cx, props)| {
let data = match get_data() { let data = match get_data() {
Some(data) => data, Some(data) => data,
None => return None, None => return None,
@ -46,7 +46,7 @@ static App1: FC<()> = |cx, props| {
/// a user is logged in. /// a user is logged in.
/// ///
/// Dioxus will throw an error in the console if the None-path is ever taken. /// Dioxus will throw an error in the console if the None-path is ever taken.
static App2: FC<()> = |cx, props| { static App2: FC<()> = |(cx, props)| {
let data = get_data()?; let data = get_data()?;
cx.render(rsx!( div { "{data}" } )) cx.render(rsx!( div { "{data}" } ))
}; };
@ -54,14 +54,14 @@ static App2: FC<()> = |cx, props| {
/// This is top-tier error handling since it displays a failure state. /// This is top-tier error handling since it displays a failure state.
/// ///
/// However, the error is lacking in context. /// However, the error is lacking in context.
static App3: FC<()> = |cx, props| match get_data() { static App3: FC<()> = |(cx, props)| match get_data() {
Some(data) => cx.render(rsx!( div { "{data}" } )), Some(data) => cx.render(rsx!( div { "{data}" } )),
None => cx.render(rsx!( div { "Failed to load data :(" } )), None => cx.render(rsx!( div { "Failed to load data :(" } )),
}; };
/// For errors that return results, it's possible short-circuit the match-based error handling with `.ok()` which converts /// For errors that return results, it's possible short-circuit the match-based error handling with `.ok()` which converts
/// a Result<T, V> into an Option<T> and lets you /// a Result<T, V> into an Option<T> and lets you
static App4: FC<()> = |cx, props| { static App4: FC<()> = |(cx, props)| {
let data = get_data_err().ok()?; let data = get_data_err().ok()?;
cx.render(rsx!( div { "{data}" } )) cx.render(rsx!( div { "{data}" } ))
}; };
@ -69,7 +69,7 @@ static App4: FC<()> = |cx, props| {
/// This is great error handling since it displays a failure state... with context! /// This is great error handling since it displays a failure state... with context!
/// ///
/// Hopefully you never need to disply a screen like this. It's rather bad taste /// Hopefully you never need to disply a screen like this. It's rather bad taste
static App5: FC<()> = |cx, props| match get_data_err() { static App5: FC<()> = |(cx, props)| match get_data_err() {
Ok(data) => cx.render(rsx!( div { "{data}" } )), Ok(data) => cx.render(rsx!( div { "{data}" } )),
Err(c) => cx.render(rsx!( div { "Failed to load data: {c}" } )), Err(c) => cx.render(rsx!( div { "Failed to load data: {c}" } )),
}; };

View File

@ -11,7 +11,7 @@
use dioxus::prelude::*; use dioxus::prelude::*;
// Returning multiple elements with rsx! or html! // Returning multiple elements with rsx! or html!
static App1: FC<()> = |cx, props| { static App1: FC<()> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
h1 { } h1 { }
h2 { } h2 { }
@ -20,7 +20,7 @@ static App1: FC<()> = |cx, props| {
}; };
// Using the Fragment component // Using the Fragment component
static App2: FC<()> = |cx, props| { static App2: FC<()> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
Fragment { Fragment {
div {} div {}
@ -31,7 +31,7 @@ static App2: FC<()> = |cx, props| {
}; };
// Using the `fragment` method on the NodeFactory // Using the `fragment` method on the NodeFactory
static App3: FC<()> = |cx, props| { static App3: FC<()> = |(cx, props)| {
cx.render(LazyNodes::new(move |fac| { cx.render(LazyNodes::new(move |fac| {
fac.fragment_from_iter([ fac.fragment_from_iter([
fac.text(format_args!("A")), fac.text(format_args!("A")),
@ -42,7 +42,7 @@ static App3: FC<()> = |cx, props| {
})) }))
}; };
pub static Example: FC<()> = |cx, props| { pub static Example: FC<()> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
App1 {} App1 {}
App2 {} App2 {}

View File

@ -19,7 +19,7 @@ h1 {color: blue;}
p {color: red;} p {color: red;}
"#; "#;
pub static Example: FC<()> = |cx, props| { pub static Example: FC<()> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
head { style { "{STYLE}" } } head { style { "{STYLE}" } }
body { body {

View File

@ -10,7 +10,7 @@
use dioxus::prelude::*; use dioxus::prelude::*;
pub static Example: FC<()> = |cx, props| { pub static Example: FC<()> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
head { head {
style: { background_color: "powderblue" } style: { background_color: "powderblue" }
@ -29,7 +29,7 @@ pub static Example: FC<()> = |cx, props| {
// .... technically the rsx! macro is slightly broken at the moment and alows styles not wrapped in style {} // .... 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.. // I haven't noticed any name collisions yet, and am tentatively leaving this behavior in..
// Don't rely on it. // Don't rely on it.
static Example2: FC<()> = |cx, props| { static Example2: FC<()> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
div { color: "red" div { color: "red"
"hello world!" "hello world!"

View File

@ -12,7 +12,7 @@
use dioxus::prelude::*; use dioxus::prelude::*;
pub static Example: FC<()> = |cx, props| { pub static Example: FC<()> = |(cx, props)| {
let example_data = use_state(cx, || 0); let example_data = use_state(cx, || 0);
let v = (0..10).map(|f| { let v = (0..10).map(|f| {

View File

@ -7,7 +7,7 @@
use dioxus::prelude::*; use dioxus::prelude::*;
pub static Example: FC<()> = |cx, props| { pub static Example: FC<()> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
ButtonList {} ButtonList {}
NonUpdatingEvents {} NonUpdatingEvents {}
@ -16,7 +16,7 @@ pub static Example: FC<()> = |cx, props| {
}; };
/// We can use `set_name` in multiple closures; the closures automatically *copy* the reference to set_name. /// We can use `set_name` in multiple closures; the closures automatically *copy* the reference to set_name.
static ButtonList: FC<()> = |cx, props| { static ButtonList: FC<()> = |(cx, props)| {
let name = use_state(cx, || "...?"); let name = use_state(cx, || "...?");
let names = ["jack", "jill", "john", "jane"] let names = ["jack", "jill", "john", "jane"]
@ -33,7 +33,7 @@ static ButtonList: FC<()> = |cx, props| {
/// This shows how listeners may be without a visible change in the display. /// This shows how listeners may be without a visible change in the display.
/// Check the console. /// Check the console.
static NonUpdatingEvents: FC<()> = |cx, props| { static NonUpdatingEvents: FC<()> = |(cx, props)| {
rsx!(cx, div { rsx!(cx, div {
button { button {
onclick: move |_| log::info!("Did not cause any updates!") onclick: move |_| log::info!("Did not cause any updates!")
@ -42,7 +42,7 @@ static NonUpdatingEvents: FC<()> = |cx, props| {
}) })
}; };
static DisablePropogation: FC<()> = |cx, props| { static DisablePropogation: FC<()> = |(cx, props)| {
rsx!(cx, rsx!(cx,
div { div {
onclick: move |_| log::info!("event propogated to the div!") onclick: move |_| log::info!("event propogated to the div!")

View File

@ -21,7 +21,7 @@ use dioxus::prelude::*;
// By default, components with no props are always memoized. // By default, components with no props are always memoized.
// A props of () is considered empty. // A props of () is considered empty.
pub static Example: FC<()> = |cx, props| { pub static Example: FC<()> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
div { "100% memoized!" } div { "100% memoized!" }
}) })
@ -35,7 +35,7 @@ pub struct MyProps1 {
name: String, name: String,
} }
pub static Example1: FC<MyProps1> = |cx, props| { pub static Example1: FC<MyProps1> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
div { "100% memoized! {props.name}" } div { "100% memoized! {props.name}" }
}) })
@ -49,7 +49,7 @@ pub struct MyProps2 {
name: std::rc::Rc<str>, name: std::rc::Rc<str>,
} }
pub static Example2: FC<MyProps2> = |cx, props| { pub static Example2: FC<MyProps2> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
div { "100% memoized! {props.name}" } div { "100% memoized! {props.name}" }
}) })

View File

@ -1,7 +1,7 @@
use dioxus::prelude::*; use dioxus::prelude::*;
fn main() {} fn main() {}
pub static Example: FC<()> = |cx, props| { pub static Example: FC<()> = |(cx, props)| {
let p = 10; let p = 10;
cx.render(rsx! { cx.render(rsx! {

View File

@ -1,7 +1,7 @@
use dioxus::prelude::*; use dioxus::prelude::*;
fn main() {} fn main() {}
pub static Example: FC<()> = |cx, props| { pub static Example: FC<()> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
div { div {

View File

@ -9,7 +9,7 @@
use dioxus::prelude::*; use dioxus::prelude::*;
pub static Example: FC<()> = |cx, props| { pub static Example: FC<()> = |(cx, props)| {
let props = MyProps { let props = MyProps {
count: 0, count: 0,
live: true, live: true,

View File

@ -1,7 +1,7 @@
use dioxus::prelude::*; use dioxus::prelude::*;
fn main() {} fn main() {}
pub static Example: FC<()> = |cx, props| { pub static Example: FC<()> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
div { div {

View File

@ -14,7 +14,7 @@ struct DogApi {
} }
const ENDPOINT: &str = "https://dog.ceo/api/breeds/image/random"; const ENDPOINT: &str = "https://dog.ceo/api/breeds/image/random";
pub static Example: FC<()> = |cx, props| { pub static Example: FC<()> = |(cx, props)| {
let doggo = use_suspense( let doggo = use_suspense(
cx, cx,
|| surf::get(ENDPOINT).recv_json::<DogApi>(), || surf::get(ENDPOINT).recv_json::<DogApi>(),

View File

@ -24,7 +24,7 @@
use dioxus::prelude::*; use dioxus::prelude::*;
pub static Example: FC<()> = |cx, props| { pub static Example: FC<()> = |(cx, props)| {
let count = use_state(cx, || 0); let count = use_state(cx, || 0);
let mut direction = use_state(cx, || 1); let mut direction = use_state(cx, || 1);

View File

@ -1,6 +1,6 @@
use dioxus::prelude::*; use dioxus::prelude::*;
pub static Example: FC<()> = |cx, props| { pub static Example: FC<()> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
div { div {

View File

@ -1,7 +1,7 @@
use dioxus::prelude::*; use dioxus::prelude::*;
use dioxus::ssr; use dioxus::ssr;
pub static Example: FC<()> = |cx, props| { pub static Example: FC<()> = |(cx, props)| {
let as_string = use_state(cx, || { let as_string = use_state(cx, || {
// Currently, SSR is only supported for whole VirtualDOMs // Currently, SSR is only supported for whole VirtualDOMs
// This is an easy/low hanging fruit to improve upon // This is an easy/low hanging fruit to improve upon
@ -15,7 +15,7 @@ pub static Example: FC<()> = |cx, props| {
}) })
}; };
static SomeApp: FC<()> = |cx, props| { static SomeApp: FC<()> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
div { style: {background_color: "blue"} div { style: {background_color: "blue"}
h1 {"Some amazing app or component"} h1 {"Some amazing app or component"}

View File

@ -93,7 +93,7 @@
//! Dioxus uses hooks for state management. Hooks are a form of state persisted between calls of the function component. //! Dioxus uses hooks for state management. Hooks are a form of state persisted between calls of the function component.
//! //!
//! ``` //! ```
//! pub pub static Example: FC<()> = |cx, props|{ //! pub pub static Example: FC<()> = |(cx, props)|{
//! let (val, set_val) = use_state(cx, || 0); //! let (val, set_val) = use_state(cx, || 0);
//! cx.render(rsx!( //! cx.render(rsx!(
//! button { onclick: move |_| set_val(val + 1) } //! button { onclick: move |_| set_val(val + 1) }
@ -156,7 +156,7 @@
//! diouxs::web::launch(Example); //! diouxs::web::launch(Example);
//! } //! }
//! //!
//! pub pub static Example: FC<()> = |cx, props|{ //! pub pub static Example: FC<()> = |(cx, props)|{
//! cx.render(rsx! { //! cx.render(rsx! {
//! div { "Hello World!" } //! div { "Hello World!" }
//! }) //! })