浏览代码

wip: polish some more things

Jonathan Kelley 3 年之前
父节点
当前提交
14961023f9

+ 12 - 10
Cargo.toml

@@ -11,18 +11,19 @@ documentation = "https://dioxuslabs.com"
 keywords = ["dom", "ui", "gui", "react", "wasm"]
 
 [dependencies]
-dioxus-core = { path = "./packages/core", version = "^0.1.3" }
-dioxus-html = { path = "./packages/html", optional = true }
-dioxus-core-macro = { path = "./packages/core-macro", optional = true }
+dioxus-core = { path = "./packages/core", version = "^0.1.4" }
+dioxus-html = { path = "./packages/html", version = "^0.1.1", optional = true }
+dioxus-core-macro = { path = "./packages/core-macro", version = "^0.1.3", optional = true }
 dioxus-hooks = { path = "./packages/hooks", optional = true }
 
-dioxus-ssr = { path = "./packages/ssr", optional = true }
-dioxus-web = { path = "./packages/web", optional = true }
+dioxus-web = { path = "./packages/web", version = "^0.0.1", optional = true }
 dioxus-desktop = { path = "./packages/desktop", optional = true }
+dioxus-ssr = { path = "./packages/ssr", optional = true }
+
 dioxus-router = { path = "./packages/router", optional = true }
 
-dioxus-mobile = { path = "./packages/mobile", optional = true }
-dioxus-liveview = { path = "./packages/liveview", optional = true }
+# dioxus-mobile = { path = "./packages/mobile", optional = true }
+# dioxus-liveview = { path = "./packages/liveview", optional = true }
 
 [features]
 default = ["macro", "hooks", "html"]
@@ -31,11 +32,13 @@ macro = ["dioxus-core-macro"]
 hooks = ["dioxus-hooks"]
 html = ["dioxus-html"]
 router = ["dioxus-router"]
-liveview = ["dioxus-liveview"]
 ssr = ["dioxus-ssr"]
 web = ["dioxus-web", "dioxus-router/web"]
 desktop = ["dioxus-desktop", "dioxus-router/desktop"]
-mobile = ["dioxus-mobile"]
+
+
+# mobile = ["dioxus-mobile"]
+# liveview = ["dioxus-liveview"]
 
 
 [workspace]
@@ -60,7 +63,6 @@ im-rc = "15.0.0"
 fxhash = "0.2.1"
 anyhow = "1.0.51"
 serde_json = "1.0.73"
-simple_logger = "1.16.0"
 
 [target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies]
 argh = "0.1.7"

+ 8 - 8
examples/README.md

@@ -64,7 +64,7 @@ Here's what a few common tasks look like in Dioxus:
 
 Nested components with children and internal state:
 ```rust
-fn App(cx: Scope<()>) -> Element {
+fn App(cx: Scope) -> Element {
   cx.render(rsx!( Toggle { "Toggle me" } ))
 }
 
@@ -86,7 +86,7 @@ fn Toggle(cx: Scope<ToggleProps>) -> Element {
 
 Controlled inputs:
 ```rust
-fn App(cx: Scope<()>) -> Element {
+fn App(cx: Scope) -> Element {
   let value = use_state(&cx, String::new);
   cx.render(rsx!( 
     input {
@@ -100,7 +100,7 @@ fn App(cx: Scope<()>) -> Element {
 
 Lists and Conditional rendering:
 ```rust
-fn App(cx: Scope<()>) -> Element {
+fn App(cx: Scope) -> Element {
   let list = (0..10).map(|i| {
     rsx!(li { key: "{i}", "Value: {i}" })
   });
@@ -128,7 +128,7 @@ static App: Component = |cx, _| rsx!(cx, div {"hello world!"});
 
 Borrowed prop contents:
 ```rust
-fn App(cx: Scope<()>) -> Element {
+fn App(cx: Scope) -> Element {
   let name = use_state(&cx, || String::from("example"));
   rsx!(cx, Child { title: name.as_str() })
 }
@@ -145,12 +145,12 @@ Global State
 ```rust
 struct GlobalState { name: String }
 
-fn App(cx: Scope<()>) -> Element {
+fn App(cx: Scope) -> Element {
   use_provide_shared_state(cx, || GlobalState { name: String::from("Toby") })
   rsx!(cx, Leaf {})
 }
 
-fn Leaf(cx: Scope<()>) -> Element {
+fn Leaf(cx: Scope) -> Element {
   let state = use_consume_shared_state::<GlobalState>(cx)?;
   rsx!(cx, "Hello {state.name}")
 }
@@ -166,7 +166,7 @@ enum Route {
   Post(id)
 }
 
-fn App(cx: Scope<()>) -> Element {
+fn App(cx: Scope) -> Element {
   let route = use_router(cx, Route::parse);
   cx.render(rsx!(div {
     {match route {
@@ -179,7 +179,7 @@ fn App(cx: Scope<()>) -> Element {
 
 Suspense 
 ```rust
-fn App(cx: Scope<()>) -> Element {
+fn App(cx: Scope) -> Element {
   let doggo = use_suspense(cx,
     || async { reqwest::get("https://dog.ceo/api/breeds/image/random").await.unwrap().json::<Response>().await.unwrap() },
     |response| cx.render(rsx!( img { src: "{response.message}" }))

+ 6 - 6
examples/async.rs

@@ -8,19 +8,19 @@ use gloo_timers::future::TimeoutFuture;
 
 #[tokio::main]
 async fn main() {
-    dioxus::desktop::launch(App);
+    dioxus::desktop::launch(app);
 }
 
-pub static App: Component = |cx| {
+fn app(cx: Scope) -> Element {
     let count = use_state(&cx, || 0);
-    let mut direction = use_state(&cx, || 1);
+    let direction = use_state(&cx, || 1);
 
     let (async_count, dir) = (count.for_async(), *direction);
 
     let task = use_coroutine(&cx, move || async move {
         loop {
             TimeoutFuture::new(250).await;
-            *async_count.get_mut() += dir;
+            *async_count.modify() += dir;
         }
     });
 
@@ -37,9 +37,9 @@ pub static App: Component = |cx| {
         button {
             "Switch counting direcion"
             onclick: move |_| {
-                direction *= -1;
+                *direction.modify() *= -1;
                 task.restart();
             }
         }
     })
-};
+}

+ 1 - 1
examples/borrowed.rs

@@ -20,7 +20,7 @@ fn main() {
     dioxus::desktop::launch(App);
 }
 
-fn App(cx: Scope<()>) -> Element {
+fn App(cx: Scope) -> Element {
     let text: &mut Vec<String> = cx.use_hook(|_| vec![String::from("abc=def")], |f| f);
 
     let first = text.get_mut(0).unwrap();

+ 97 - 93
examples/calculator.rs

@@ -1,3 +1,5 @@
+#![allow(non_snake_case)]
+
 /*
 This example is a simple iOS-style calculator. This particular example can run any platform - Web, Mobile, Desktop.
 This calculator version uses React-style state management. All state is held as individual use_states.
@@ -10,10 +12,10 @@ use dioxus::prelude::*;
 use separator::Separatable;
 
 fn main() {
-    dioxus::desktop::launch(APP);
+    dioxus::desktop::launch(app);
 }
 
-static APP: Component = |cx| {
+fn app(cx: Scope) -> Element {
     let cur_val = use_state(&cx, || 0.0_f64);
     let operator = use_state(&cx, || None as Option<&'static str>);
     let display_value = use_state(&cx, || String::from(""));
@@ -21,109 +23,111 @@ static APP: Component = |cx| {
     let toggle_percent = move |_| todo!();
     let input_digit = move |num: u8| display_value.modify().push_str(num.to_string().as_str());
 
-    rsx!(cx, div {
-        class: "calculator",
-        onkeydown: move |evt| match evt.key_code {
-            KeyCode::Add => operator.set(Some("+")),
-            KeyCode::Subtract => operator.set(Some("-")),
-            KeyCode::Divide => operator.set(Some("/")),
-            KeyCode::Multiply => operator.set(Some("*")),
-            KeyCode::Num0 => input_digit(0),
-            KeyCode::Num1 => input_digit(1),
-            KeyCode::Num2 => input_digit(2),
-            KeyCode::Num3 => input_digit(3),
-            KeyCode::Num4 => input_digit(4),
-            KeyCode::Num5 => input_digit(5),
-            KeyCode::Num6 => input_digit(6),
-            KeyCode::Num7 => input_digit(7),
-            KeyCode::Num8 => input_digit(8),
-            KeyCode::Num9 => input_digit(9),
-            KeyCode::Backspace => {
-                if !display_value.as_str().eq("0") {
-                    display_value.modify().pop();
+    cx.render(rsx!(
+        div { class: "calculator",
+            onkeydown: move |evt| match evt.key_code {
+                KeyCode::Add => operator.set(Some("+")),
+                KeyCode::Subtract => operator.set(Some("-")),
+                KeyCode::Divide => operator.set(Some("/")),
+                KeyCode::Multiply => operator.set(Some("*")),
+                KeyCode::Num0 => input_digit(0),
+                KeyCode::Num1 => input_digit(1),
+                KeyCode::Num2 => input_digit(2),
+                KeyCode::Num3 => input_digit(3),
+                KeyCode::Num4 => input_digit(4),
+                KeyCode::Num5 => input_digit(5),
+                KeyCode::Num6 => input_digit(6),
+                KeyCode::Num7 => input_digit(7),
+                KeyCode::Num8 => input_digit(8),
+                KeyCode::Num9 => input_digit(9),
+                KeyCode::Backspace => {
+                    if !display_value.as_str().eq("0") {
+                        display_value.modify().pop();
+                    }
                 }
+                _ => {}
             }
-            _ => {}
-        }
-        div { class: "calculator-display", {[format_args!("{}", cur_val.separated_string())]} }
-        div { class: "input-keys"
-            div { class: "function-keys"
-                CalculatorKey {
-                    {[if display_value == "0" { "C" } else { "AC" }]}
-                    name: "key-clear",
-                    onclick: move |_| {
-                        display_value.set("0".to_string());
-                        if display_value != "0" {
-                            operator.set(None);
-                            cur_val.set(0.0);
+            div { class: "calculator-display", {[cur_val.separated_string()]} }
+            div { class: "input-keys"
+                div { class: "function-keys"
+                    CalculatorKey {
+                        {[if display_value == "0" { "C" } else { "AC" }]}
+                        name: "key-clear",
+                        onclick: move |_| {
+                            display_value.set("0".to_string());
+                            if display_value != "0" {
+                                operator.set(None);
+                                cur_val.set(0.0);
+                            }
                         }
                     }
+                    CalculatorKey {
+                        "±"
+                        name: "key-sign",
+                        onclick: move |_| {
+                            if display_value.starts_with("-") {
+                                display_value.set(display_value.trim_start_matches("-").to_string())
+                            } else {
+                                display_value.set(format!("-{}", *display_value))
+                            }
+                        },
+                    }
+                    CalculatorKey {
+                        "%"
+                        onclick: {toggle_percent}
+                        name: "key-percent",
+                    }
                 }
-                CalculatorKey {
-                    "±"
-                    name: "key-sign",
-                    onclick: move |_| {
-                        if display_value.starts_with("-") {
-                            display_value.set(display_value.trim_start_matches("-").to_string())
-                        } else {
-                            display_value.set(format!("-{}", *display_value))
-                        }
-                    },
-                }
-                CalculatorKey {
-                    "%"
-                    onclick: {toggle_percent}
-                    name: "key-percent",
-                }
-            }
-            div { class: "digit-keys"
-                CalculatorKey { name: "key-0", onclick: move |_| input_digit(0), "0" }
-                CalculatorKey { name: "key-dot", onclick: move |_| display_value.modify().push_str("."), "●" }
+                div { class: "digit-keys"
+                    CalculatorKey { name: "key-0", onclick: move |_| input_digit(0), "0" }
+                    CalculatorKey { name: "key-dot", onclick: move |_| display_value.modify().push_str("."), "●" }
 
-                {(1..9).map(|k| rsx!{
-                    CalculatorKey { key: "{k}", name: "key-{k}", onclick: move |_| input_digit(k), "{k}" }
-                })}
-            }
-            div { class: "operator-keys"
-                CalculatorKey { name: "key-divide", onclick: move |_| operator.set(Some("/")) "÷" }
-                CalculatorKey { name: "key-multiply", onclick: move |_| operator.set(Some("*")) "×" }
-                CalculatorKey { name: "key-subtract", onclick: move |_| operator.set(Some("-")) "−" }
-                CalculatorKey { name: "key-add", onclick: move |_| operator.set(Some("+")) "+" }
-                CalculatorKey {
-                    "="
-                    name: "key-equals",
-                    onclick: move |_| {
-                        if let Some(op) = operator.as_ref() {
-                            let rhs = display_value.parse::<f64>().unwrap();
-                            let new_val = match *op {
-                                "+" => *cur_val + rhs,
-                                "-" => *cur_val - rhs,
-                                "*" => *cur_val * rhs,
-                                "/" => *cur_val / rhs,
-                                _ => unreachable!(),
-                            };
-                            cur_val.set(new_val);
-                            display_value.set(new_val.to_string());
-                            operator.set(None);
-                        }
-                    },
+                    {(1..9).map(|k| rsx!{
+                        CalculatorKey { key: "{k}", name: "key-{k}", onclick: move |_| input_digit(k), "{k}" }
+                    })}
+                }
+                div { class: "operator-keys"
+                    CalculatorKey { name: "key-divide", onclick: move |_| operator.set(Some("/")) "÷" }
+                    CalculatorKey { name: "key-multiply", onclick: move |_| operator.set(Some("*")) "×" }
+                    CalculatorKey { name: "key-subtract", onclick: move |_| operator.set(Some("-")) "−" }
+                    CalculatorKey { name: "key-add", onclick: move |_| operator.set(Some("+")) "+" }
+                    CalculatorKey {
+                        "="
+                        name: "key-equals",
+                        onclick: move |_| {
+                            if let Some(op) = operator.as_ref() {
+                                let rhs = display_value.parse::<f64>().unwrap();
+                                let new_val = match *op {
+                                    "+" => *cur_val + rhs,
+                                    "-" => *cur_val - rhs,
+                                    "*" => *cur_val * rhs,
+                                    "/" => *cur_val / rhs,
+                                    _ => unreachable!(),
+                                };
+                                cur_val.set(new_val);
+                                display_value.set(new_val.to_string());
+                                operator.set(None);
+                            }
+                        },
+                    }
                 }
             }
         }
-    })
-};
+    ))
+}
 
-#[derive(Props)]
-struct CalculatorKeyProps<'a> {
+#[inline_props]
+fn CalculatorKey<'a>(
+    cx: Scope,
     name: &'static str,
     onclick: &'a dyn Fn(Arc<MouseEvent>),
     children: Element<'a>,
-}
-
-fn CalculatorKey<'a>(cx: Scope<'a, CalculatorKeyProps<'a>>) -> Element {
-    rsx!(cx, button {
-        class: "calculator-key {cx.props.name}"
-        onclick: {cx.props.onclick}
-        {&cx.props.children}
+) -> Element {
+    cx.render(rsx! {
+        button {
+            class: "calculator-key {name}"
+            onclick: {onclick}
+            {children}
+        }
     })
 }

+ 1 - 1
examples/core/jsframework.rs

@@ -15,7 +15,7 @@ fn main() {
     assert!(g.edits.len() > 1);
 }
 
-fn App((cx, props): Scope<()>) -> Element {
+fn App((cx, props): Scope) -> Element {
     let mut rng = SmallRng::from_entropy();
     let rows = (0..10_000_usize).map(|f| {
         let label = Label::new(&mut rng);

+ 0 - 5
examples/desktop/todomvc.rs

@@ -5,15 +5,10 @@ use dioxus_core::prelude::*;
 use dioxus_core_macro::*;
 use dioxus_hooks::*;
 use dioxus_html as dioxus_elements;
-use simple_logger::SimpleLogger;
 
 use std::collections::HashMap;
 
 fn main() {
-    if cfg!(debug_assertions) {
-        SimpleLogger::new().init().unwrap();
-    }
-
     dioxus_desktop::launch(App)
 }
 

+ 0 - 1
examples/file_explorer.rs

@@ -8,7 +8,6 @@
 use dioxus::prelude::*;
 
 fn main() {
-    // simple_logger::init_with_level(log::Level::Debug);
     dioxus::desktop::launch_cfg(App, |c| {
         c.with_window(|w| {
             w.with_resizable(true).with_inner_size(

+ 1 - 1
examples/hello_world.rs

@@ -4,7 +4,7 @@ fn main() {
     dioxus::desktop::launch(app);
 }
 
-fn app(cx: Scope<()>) -> Element {
+fn app(cx: Scope) -> Element {
     cx.render(rsx! (
         div { "Hello, world!" }
     ))

+ 4 - 3
examples/readme.rs

@@ -3,18 +3,19 @@
 //! The example from the README.md.
 
 use dioxus::prelude::*;
+
 fn main() {
     dioxus::desktop::launch(App);
 }
 
 static App: Component = |cx| {
-    let mut count = use_state(&cx, || 0);
+    let count = use_state(&cx, || 0);
 
     cx.render(rsx! {
         div {
             h1 { "High-Five counter: {count}" }
-            button { onclick: move |_| count += 1, "Up high!" }
-            button { onclick: move |_| count -= 1, "Down low!" }
+            button { onclick: move |_| *count.modify() += 1, "Up high!" }
+            button { onclick: move |_| *count.modify() -= 1, "Down low!" }
         }
     })
 };

+ 11 - 7
examples/tasks.rs

@@ -2,26 +2,30 @@
 //!
 //! The example from the README.md.
 
+use dioxus::prelude::*;
 use std::time::Duration;
 
-use dioxus::prelude::*;
 fn main() {
     dioxus::desktop::launch(app);
 }
 
-fn app(cx: Scope<()>) -> Element {
-    let mut count = use_state(&cx, || 0);
+fn app(cx: Scope) -> Element {
+    let count = use_state(&cx, || 0);
 
-    cx.push_future(|| async move {
-        tokio::time::sleep(Duration::from_millis(100)).await;
-        count += 1;
+    use_future(&cx, || {
+        for_async![count];
+        async move {
+            while let _ = tokio::time::sleep(Duration::from_millis(1000)).await {
+                *count.modify() += 1;
+            }
+        }
     });
 
     cx.render(rsx! {
         div {
             h1 { "High-Five counter: {count}" }
             button {
-                onclick: move |_| count +=1 ,
+                onclick: move |_| *count.modify() += 1,
                 "Click me!"
             }
         }

+ 6 - 7
examples/webview_web.rs

@@ -1,4 +1,3 @@
-#![allow(non_upper_case_globals, non_snake_case)]
 //! Example: Webview Renderer
 //! -------------------------
 //!
@@ -13,17 +12,17 @@
 use dioxus::prelude::*;
 
 fn main() {
-    dioxus::web::launch(App);
+    dioxus::desktop::launch(app);
 }
 
-static App: Component = |cx| {
-    let mut count = use_state(&cx, || 0);
+fn app(cx: Scope) -> Element {
+    let count = use_state(&cx, || 0);
 
     cx.render(rsx! {
         div {
             h1 { "Hifive counter: {count}" }
-            button { onclick: move |_| count += 1, "Up high!" }
-            button { onclick: move |_| count -= 1, "Down low!" }
+            button { onclick: move |_| *count.modify() += 1, "Up high!" }
+            button { onclick: move |_| *count.modify() -= 1, "Down low!" }
         }
     })
-};
+}

+ 1 - 1
packages/core-macro/src/lib.rs

@@ -161,7 +161,7 @@ pub fn derive_typed_builder(input: proc_macro::TokenStream) -> proc_macro::Token
 ///     pub struct BallerProps {}
 ///
 ///     /// This component totally balls
-///     pub fn Baller(cx: Scope<()>) -> DomTree {
+///     pub fn Baller(cx: Scope) -> DomTree {
 ///         todo!()
 ///     }
 /// }

+ 0 - 1
packages/core/Cargo.toml

@@ -50,7 +50,6 @@ anyhow = "1.0.42"
 dioxus-html = { path = "../html" }
 fern = { version = "0.6.0", features = ["colored"] }
 rand = { version = "0.8.4", features = ["small_rng"] }
-simple_logger = "1.13.0"
 dioxus-core-macro = { path = "../core-macro", version = "^0.1.2" }
 criterion = "0.3.5"
 thiserror = "1.0.30"

+ 1 - 1
packages/core/README.md

@@ -6,7 +6,7 @@ To build new apps with Dioxus or to extend the ecosystem with new hooks or compo
 
 
 ```rust
-fn app(cx: Scope<()>) -> Element {
+fn app(cx: Scope) -> Element {
     rsx!(cx, div { "hello world" })
 }
 

+ 1 - 1
packages/core/examples/component_children.rs

@@ -11,7 +11,7 @@ fn main() {
     dbg!(edits);
 }
 
-fn parent(cx: Scope<()>) -> Element {
+fn parent(cx: Scope) -> Element {
     let value = cx.use_hook(|_| String::new(), |f| f);
 
     cx.render(rsx! {

+ 1 - 1
packages/core/examples/works.rs

@@ -9,7 +9,7 @@ fn main() {
     let _ = VirtualDom::new(parent);
 }
 
-fn parent(cx: Scope<()>) -> Element {
+fn parent(cx: Scope) -> Element {
     let value = cx.use_hook(|_| String::new(), |f| f);
 
     cx.render(rsx! {

+ 11 - 1
packages/core/src/nodes.rs

@@ -84,7 +84,7 @@ pub enum VNode<'src> {
     /// # Example
     ///
     /// ```rust, ignore
-    /// fn Example(cx: Scope<()>) -> Element {
+    /// fn Example(cx: Scope) -> Element {
     ///     ...
     /// }
     ///
@@ -740,6 +740,12 @@ impl IntoVNode<'_> for &'static str {
     }
 }
 
+impl IntoVNode<'_> for String {
+    fn into_vnode(self, cx: NodeFactory) -> VNode {
+        cx.text(format_args!("{}", self))
+    }
+}
+
 impl IntoVNode<'_> for Arguments<'_> {
     fn into_vnode(self, cx: NodeFactory) -> VNode {
         cx.text(self)
@@ -758,3 +764,7 @@ impl<'a> IntoVNode<'a> for &VNode<'a> {
         self.decouple()
     }
 }
+
+trait IntoAcceptedVnode<'a> {
+    fn into_accepted_vnode(self, cx: NodeFactory<'a>) -> VNode<'a>;
+}

+ 1 - 1
packages/core/src/scopes.rs

@@ -490,7 +490,7 @@ impl ScopeState {
     /// # Example
     ///
     /// ```rust, ignore
-    /// fn App(cx: Scope<()>) -> Element {
+    /// fn App(cx: Scope) -> Element {
     ///     rsx!(cx, div { "Subtree {id}"})
     /// };
     /// ```

+ 9 - 9
packages/core/src/virtual_dom.rs

@@ -80,7 +80,7 @@ use std::{any::Any, collections::VecDeque, iter::FromIterator, pin::Pin, sync::A
 /// Putting everything together, you can build an event loop around Dioxus by using the methods outlined above.
 ///
 /// ```rust, ignore
-/// fn App(cx: Scope<()>) -> Element {
+/// fn App(cx: Scope) -> Element {
 ///     cx.render(rsx!{
 ///         div { "Hello World" }
 ///     })
@@ -127,7 +127,7 @@ impl VirtualDom {
     ///
     /// # Example
     /// ```rust, ignore
-    /// fn Example(cx: Scope<()>) -> Element  {
+    /// fn Example(cx: Scope) -> Element  {
     ///     cx.render(rsx!( div { "hello world" } ))
     /// }
     ///
@@ -388,7 +388,7 @@ impl VirtualDom {
     /// # Example
     ///
     /// ```rust, ignore
-    /// fn App(cx: Scope<()>) -> Element {
+    /// fn App(cx: Scope) -> Element {
     ///     cx.render(rsx!( div {"hello"} ))
     /// }
     ///
@@ -544,7 +544,7 @@ impl VirtualDom {
     /// Useful when needing to render nodes from outside the VirtualDom, such as in a test.
     ///
     /// ```rust
-    /// fn Base(cx: Scope<()>) -> Element {
+    /// fn Base(cx: Scope) -> Element {
     ///     rsx!(cx, div {})
     /// }
     ///
@@ -564,7 +564,7 @@ impl VirtualDom {
     /// Useful when needing to render nodes from outside the VirtualDom, such as in a test.
     ///
     /// ```rust
-    /// fn Base(cx: Scope<()>) -> Element {
+    /// fn Base(cx: Scope) -> Element {
     ///     rsx!(cx, div {})
     /// }
     ///
@@ -586,7 +586,7 @@ impl VirtualDom {
     ///
     ///
     /// ```rust
-    /// fn Base(cx: Scope<()>) -> Element {
+    /// fn Base(cx: Scope) -> Element {
     ///     rsx!(cx, div {})
     /// }
     ///
@@ -609,7 +609,7 @@ impl VirtualDom {
     ///
     ///
     /// ```rust
-    /// fn Base(cx: Scope<()>) -> Element {
+    /// fn Base(cx: Scope) -> Element {
     ///     rsx!(cx, div {})
     /// }
     ///
@@ -753,7 +753,7 @@ pub enum SchedulerMsg {
 ///
 /// # Example
 /// ```rust
-/// fn App(cx: Scope<()>) -> Element {
+/// fn App(cx: Scope) -> Element {
 ///     rsx!(cx, div {
 ///         onclick: move |_| println!("Clicked!")
 ///     })
@@ -871,7 +871,7 @@ impl<'a, const A: bool> FragmentBuilder<'a, A> {
 /// ## Example
 ///
 /// ```rust, ignore
-/// fn App(cx: Scope<()>) -> Element {
+/// fn App(cx: Scope) -> Element {
 ///     cx.render(rsx!{
 ///         CustomCard {
 ///             h1 {}2

+ 1 - 1
packages/core/tests/borrowedstate.rs

@@ -10,7 +10,7 @@ fn test_borrowed_state() {
     let _ = VirtualDom::new(Parent);
 }
 
-fn Parent(cx: Scope<()>) -> Element {
+fn Parent(cx: Scope) -> Element {
     let value = cx.use_hook(|_| String::new(), |f| &*f);
 
     cx.render(rsx! {

+ 7 - 7
packages/core/tests/miri_stress.rs

@@ -28,7 +28,7 @@ fn new_dom<P: 'static + Send>(app: Component<P>, props: P) -> VirtualDom {
 /// In debug, this should also toss a warning.
 #[test]
 fn test_memory_leak() {
-    fn app(cx: Scope<()>) -> Element {
+    fn app(cx: Scope) -> Element {
         let val = cx.use_hook(|_| 0, |f| f);
 
         *val += 1;
@@ -68,7 +68,7 @@ fn test_memory_leak() {
         })
     }
 
-    fn child(cx: Scope<()>) -> Element {
+    fn child(cx: Scope) -> Element {
         rsx!(cx, div { "goodbye world" })
     }
 
@@ -85,7 +85,7 @@ fn test_memory_leak() {
 
 #[test]
 fn memo_works_properly() {
-    fn app(cx: Scope<()>) -> Element {
+    fn app(cx: Scope) -> Element {
         let val = cx.use_hook(|_| 0, |f| f);
 
         *val += 1;
@@ -164,7 +164,7 @@ fn free_works_on_root_props() {
 
 #[test]
 fn free_works_on_borrowed() {
-    fn app(cx: Scope<()>) -> Element {
+    fn app(cx: Scope) -> Element {
         cx.render(rsx! {
             child(a: "alpha", b: "asd".to_string())
         })
@@ -203,7 +203,7 @@ fn free_works_on_root_hooks() {
         }
     }
 
-    fn app(cx: Scope<()>) -> Element {
+    fn app(cx: Scope) -> Element {
         let name = cx.use_hook(|_| Droppable(String::from("asd")), |f| f);
         rsx!(cx, div { "{name.0}" })
     }
@@ -214,7 +214,7 @@ fn free_works_on_root_hooks() {
 
 #[test]
 fn old_props_arent_stale() {
-    fn app(cx: Scope<()>) -> Element {
+    fn app(cx: Scope) -> Element {
         dbg!("rendering parent");
         let cnt = cx.use_hook(|_| 0, |f| f);
         *cnt += 1;
@@ -261,7 +261,7 @@ fn old_props_arent_stale() {
 
 #[test]
 fn basic() {
-    fn app(cx: Scope<()>) -> Element {
+    fn app(cx: Scope) -> Element {
         rsx!(cx, div {
             child(a: "abcdef".to_string())
         })

+ 0 - 1
packages/desktop/Cargo.toml

@@ -37,4 +37,3 @@ tokio_runtime = ["tokio"]
 
 [dev-dependencies]
 dioxus-hooks = { path = "../hooks" }
-simple_logger = "1.13.0"

+ 10 - 14
packages/desktop/examples/async.rs

@@ -9,22 +9,18 @@ fn main() {
     dioxus_desktop::launch(app);
 }
 
-fn app(cx: Scope<()>) -> Element {
+fn app(cx: Scope) -> Element {
     let count = use_state(&cx, || 0);
 
-    // push the futureo on initialization
-    cx.use_hook(
-        |_| {
-            cx.push_future({
-                let count = count.for_async();
-                async move {
-                    tokio::time::sleep(Duration::from_millis(1000)).await;
-                    *count.get_mut() += 1;
-                }
-            });
-        },
-        |_| {},
-    );
+    use_future(&cx, || {
+        let count = count.for_async();
+        async move {
+            loop {
+                tokio::time::sleep(Duration::from_millis(1000)).await;
+                *count.modify() += 1;
+            }
+        }
+    });
 
     cx.render(rsx! {
         div {

+ 4 - 43
packages/hooks/README.md

@@ -4,58 +4,19 @@ This crate includes some basic useful hooks for dioxus:
 
 - use_state
 - use_ref
-- use_collection
-- use_task
-- use_signal
+- use_future
+- use_coroutine
 
 ## use_state
 
-The king daddy of state hooks.
+The primary mechanism of stored state.
 
 You can always use it "normally" with the `split` method:
 
 ```rust
-// Normal usage:
+// Rusty-smart-pointer usage:
 let value = use_state(&cx, || 10);
 
 // "Classic" usage:
 let (value, set_value) = use_state(&cx, || 0).split();
 ```
-
-## use_ref
-
-
-## use_rwlock
-A multithreaded form of RwLock for use in tasks
-```rust
-let val = use_rwlock(cx, || 10);
-use_task((), || async loop {
-    *val.write().unwrap() += 1;
-    async_std::task::delay(Duration::from_ms(1000)).await;
-});
-use_task((), || async loop {
-    *val.write().unwrap() -= 1;
-    async_std::task::delay(Duration::from_ms(500)).await;
-});
-```
-
-## use_hashmap
-Store a memoized collection with similar semantics to use_state. Comes with a bunch of utility methods to make working with collections easier. Is essentially a wrapper over the immutable hashmap in im-rc.
-
-```rust
-let todos = use_hashmap(cx, |map| map.insert("bob", "bill"));
-cx.render(rsx!(
-    button { onclick: move |_| todos.insert("bob", "bill")
-        "add random todo"
-    }
-)
-
-```
-
-## use_task
-
-use_task submits a task to the dioxus task queue to be progressed during Dioxus's async event loop. The task must not return anything
-
-
-## use_signal
-

+ 43 - 3
packages/hooks/src/lib.rs

@@ -1,5 +1,5 @@
 mod usestate;
-pub use usestate::{use_state, AsyncUseState, UseState};
+pub use usestate::{use_state, UseState};
 
 mod useref;
 pub use useref::*;
@@ -16,5 +16,45 @@ pub use usefuture::*;
 mod usesuspense;
 pub use usesuspense::*;
 
-// mod usemodel;
-// pub use usemodel::*;
+#[macro_export]
+macro_rules! to_owned {
+    ($($es:ident),+) => {$(
+        #[allow(unused_mut)]
+        let mut $es = $es.to_owned();
+    )*}
+}
+
+/// Calls `for_async` on the series of paramters.
+///
+/// If the type is Clone, then it will be cloned. However, if the type is not `clone`
+/// then it must have a `for_async` method for Rust to lower down into.
+///
+/// See: how use_state implements `for_async` but *not* through the trait.
+#[macro_export]
+macro_rules! for_async {
+    ($($es:ident),+) => {$(
+        #[allow(unused_mut)]
+        let mut $es = $es.for_async();
+    )*}
+}
+
+/// This is a marker trait that uses decoherence.
+///
+/// It is *not* meant for hooks to actually implement, but rather defer to their
+/// underlying implementation if they *don't* implement the trait.
+///
+///
+pub trait AsyncHook {
+    type Output;
+    fn for_async(self) -> Self::Output;
+}
+
+impl<T> AsyncHook for T
+where
+    T: ToOwned<Owned = T>,
+{
+    type Output = T;
+    fn for_async(self) -> Self::Output {
+        self
+    }
+}

+ 15 - 119
packages/hooks/src/usestate.rs

@@ -2,20 +2,9 @@ use dioxus_core::prelude::*;
 use std::{
     cell::{Cell, Ref, RefCell, RefMut},
     fmt::{Debug, Display},
-    ops::Not,
     rc::Rc,
 };
 
-pub trait UseStateA<'a, T> {
-    fn use_state(&self, initial_state_fn: impl FnOnce() -> T) -> UseState<'a, T>;
-}
-
-impl<'a, P, T> UseStateA<'a, T> for Scope<'a, P> {
-    fn use_state(&self, initial_state_fn: impl FnOnce() -> T) -> UseState<'a, T> {
-        use_state(self.scope, initial_state_fn)
-    }
-}
-
 /// Store state between component renders!
 ///
 /// ## Dioxus equivalent of useState, designed for Rust
@@ -109,6 +98,7 @@ where
         UseState { inner: self.inner }
     }
 }
+
 impl<T: Debug> Debug for UseState<'_, T> {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         write!(f, "{:?}", self.inner.current_val)
@@ -157,21 +147,21 @@ impl<'a, T: 'static> UseState<'a, T> {
         })
     }
 
-    pub fn for_async(&self) -> AsyncUseState<T> {
-        AsyncUseState {
-            re_render: self.inner.update_callback.clone(),
-            wip: self.inner.wip.clone(),
-            inner: self.inner.current_val.clone(),
-        }
+    pub fn for_async(self) -> UseState<'static, T> {
+        todo!()
     }
 
-    pub fn split_for_async(&'a self) -> (&'a Self, AsyncUseState<T>) {
-        (self, self.for_async())
+    pub fn wtih(self, f: impl FnOnce(&mut T)) {
+        let mut val = self.inner.wip.borrow_mut();
+
+        if let Some(inner) = val.as_mut() {
+            f(inner);
+        }
     }
 }
 
 impl<'a, T: 'static + ToOwned<Owned = T>> UseState<'a, T> {
-    /// Gain mutable access to the new value via RefMut.
+    /// Gain mutable access to the new value via [`RefMut`].
     ///
     /// If `modify` is called, then the component will re-render.
     ///
@@ -207,57 +197,10 @@ impl<'a, T> std::ops::Deref for UseState<'a, T> {
     }
 }
 
-use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
-
-impl<'a, T: Copy + Add<T, Output = T>> Add<T> for UseState<'a, T> {
-    type Output = T;
-
-    fn add(self, rhs: T) -> Self::Output {
-        self.inner.current_val.add(rhs)
-    }
-}
-impl<'a, T: Copy + Add<T, Output = T>> AddAssign<T> for UseState<'a, T> {
-    fn add_assign(&mut self, rhs: T) {
-        self.set(self.inner.current_val.add(rhs));
-    }
-}
-impl<'a, T: Copy + Sub<T, Output = T>> Sub<T> for UseState<'a, T> {
-    type Output = T;
-
-    fn sub(self, rhs: T) -> Self::Output {
-        self.inner.current_val.sub(rhs)
-    }
-}
-impl<'a, T: Copy + Sub<T, Output = T>> SubAssign<T> for UseState<'a, T> {
-    fn sub_assign(&mut self, rhs: T) {
-        self.set(self.inner.current_val.sub(rhs));
-    }
-}
-
-/// MUL
-impl<'a, T: Copy + Mul<T, Output = T>> Mul<T> for UseState<'a, T> {
-    type Output = T;
-
-    fn mul(self, rhs: T) -> Self::Output {
-        self.inner.current_val.mul(rhs)
-    }
-}
-impl<'a, T: Copy + Mul<T, Output = T>> MulAssign<T> for UseState<'a, T> {
-    fn mul_assign(&mut self, rhs: T) {
-        self.set(self.inner.current_val.mul(rhs));
-    }
-}
-/// DIV
-impl<'a, T: Copy + Div<T, Output = T>> Div<T> for UseState<'a, T> {
-    type Output = T;
-
-    fn div(self, rhs: T) -> Self::Output {
-        self.inner.current_val.div(rhs)
-    }
-}
-impl<'a, T: Copy + Div<T, Output = T>> DivAssign<T> for UseState<'a, T> {
-    fn div_assign(&mut self, rhs: T) {
-        self.set(self.inner.current_val.div(rhs));
+// enable displaty for the handle
+impl<'a, T: 'static + Display> std::fmt::Display for UseState<'a, T> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "{}", self.inner.current_val)
     }
 }
 impl<'a, V, T: PartialEq<V>> PartialEq<V> for UseState<'a, T> {
@@ -265,57 +208,10 @@ impl<'a, V, T: PartialEq<V>> PartialEq<V> for UseState<'a, T> {
         self.get() == other
     }
 }
-impl<'a, O, T: Not<Output = O> + Copy> Not for UseState<'a, T> {
+impl<'a, O, T: std::ops::Not<Output = O> + Copy> std::ops::Not for UseState<'a, T> {
     type Output = O;
 
     fn not(self) -> Self::Output {
         !*self.get()
     }
 }
-
-// enable displaty for the handle
-impl<'a, T: 'static + Display> std::fmt::Display for UseState<'a, T> {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        write!(f, "{}", self.inner.current_val)
-    }
-}
-
-/// A less ergonmic but still capable form of use_state that's valid for `static lifetime
-pub struct AsyncUseState<T: 'static> {
-    inner: Rc<T>,
-    re_render: Rc<dyn Fn()>,
-    wip: Rc<RefCell<Option<T>>>,
-}
-
-impl<T: ToOwned<Owned = T>> AsyncUseState<T> {
-    pub fn get_mut<'a>(&'a self) -> RefMut<'a, T> {
-        // make sure we get processed
-        {
-            let mut wip = self.wip.borrow_mut();
-            if wip.is_none() {
-                *wip = Some(self.inner.as_ref().to_owned());
-            }
-            (self.re_render)();
-        }
-        // Bring out the new value, cloning if it we need to
-        // "get_mut" is locked behind "ToOwned" to make it explicit that cloning occurs to use this
-        RefMut::map(self.wip.borrow_mut(), |slot| {
-            //
-            slot.as_mut().unwrap()
-        })
-    }
-}
-impl<T> AsyncUseState<T> {
-    pub fn set(&mut self, val: T) {
-        (self.re_render)();
-        *self.wip.borrow_mut() = Some(val);
-    }
-
-    // pub fn get(&self) -> Ref<'_, T> {
-    //     self.wip.borrow
-    // }
-
-    pub fn get_rc(&self) -> &Rc<T> {
-        &self.inner
-    }
-}

+ 0 - 2
packages/html/Cargo.toml

@@ -9,14 +9,12 @@ repository = "https://github.com/DioxusLabs/dioxus/"
 homepage = "https://dioxuslabs.com"
 documentation = "https://docs.rs/dioxus"
 keywords = ["dom", "ui", "gui", "react", "wasm"]
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
 dioxus-core = { path = "../core", version = "^0.1.4" }
 serde = { version = "1", features = ["derive"], optional = true }
 serde_repr = { version = "0.1", optional = true }
 
-
 [features]
 default = []
 serialize = ["serde", "serde_repr"]

+ 1 - 1
packages/liveview/README.md

@@ -39,7 +39,7 @@ async fn order_shoes(mut req: WebsocketRequest) -> Response {
     dioxus::liveview::launch(App, stream).await;    
 }
 
-fn App(cx: Scope<()>) -> Element {
+fn App(cx: Scope) -> Element {
     let mut count = use_state(&cx, || 0);
     cx.render(rsx!(
         button { onclick: move |_| count += 1, "Incr" }

+ 1 - 4
packages/mobile/Cargo.toml

@@ -12,7 +12,7 @@ keywords = ["dom", "ui", "gui", "react", "wasm"]
 [dependencies]
 anyhow = "1.0"
 # cacao = { git = "https://github.com/ryanmcgrath/cacao" }
-dioxus-core = { path = "../core", version ="^0.1.3"}
+dioxus-core = { path = "../core", version = "^0.1.3" }
 log = "0.4.14"
 serde = "1.0.126"
 serde_json = "1.0.64"
@@ -23,6 +23,3 @@ wry = "0.12.2"
 android_logger = "0.9.0"
 log = "0.4.11"
 ndk-glue = "0.2.1"
-
-[target.'cfg(not(target_os = "android"))'.dependencies]
-simple_logger = "1.11.0"

+ 0 - 5
packages/mobile/src/lib.rs

@@ -20,10 +20,6 @@ use wry::{
 mod dom;
 use dom::*;
 
-fn init_logging() {
-    simple_logger::SimpleLogger::new().init().unwrap();
-}
-
 static HTML_CONTENT: &'static str = include_str!("../../desktop/src/index.html");
 
 pub fn launch(root: Component, builder: fn(WindowBuilder) -> WindowBuilder) -> anyhow::Result<()> {
@@ -187,7 +183,6 @@ impl<T: 'static + Send> WebviewRenderer<T> {
 }
 
 fn main() {
-    init_logging();
     let event_loop = EventLoop::new();
 
     let mut weviews = HashMap::new();

+ 9 - 9
src/lib.rs

@@ -46,7 +46,7 @@
 //!     dioxus::desktop::launch(app);
 //! }
 //!
-//! fn app(cx: Scope<()>) -> Element {
+//! fn app(cx: Scope) -> Element {
 //!     cx.render(rsx!("hello world!"))
 //! }
 //! ```
@@ -57,7 +57,7 @@
 //! For components with no explicit properties, we can use the `()` type. In Dioxus, all properties are memoized by default!
 //!
 //! ```rust
-//! fn App(cx: Scope<()>) -> Element {
+//! fn App(cx: Scope) -> Element {
 //!     cx.render(rsx!(
 //!         Header {
 //!             title: "My App",
@@ -91,7 +91,7 @@
 //! While components are reusable forms of UI elements, hooks are reusable forms of logic. All hooks start with `use_`. We can use hooks to declare state.
 //!
 //! ```rust
-//! fn app(cx: Scope<()>) -> Element {
+//! fn app(cx: Scope) -> Element {
 //!     let name = use_state(&cx, || "world");
 //!
 //!     rsx!(cx, "hello {name}!")
@@ -137,7 +137,7 @@
 //!     dioxus::desktop::launch(App);
 //! }
 //!
-//! fn App(cx: Scope<()>) -> Element {
+//! fn App(cx: Scope) -> Element {
 //!     let mut count = use_state(&cx, || 0);
 //!
 //!     cx.render(rsx!(
@@ -187,20 +187,20 @@ pub use dioxus_core as core;
 #[cfg(feature = "hooks")]
 pub use dioxus_hooks as hooks;
 
+#[cfg(feature = "router")]
+pub use dioxus_router as router;
+
 #[cfg(feature = "ssr")]
 pub use dioxus_ssr as ssr;
 
 #[cfg(feature = "web")]
 pub use dioxus_web as web;
 
-#[cfg(feature = "mobile")]
-pub use dioxus_mobile as mobile;
-
 #[cfg(feature = "desktop")]
 pub use dioxus_desktop as desktop;
 
-#[cfg(feature = "router")]
-pub use dioxus_router as router;
+// #[cfg(feature = "mobile")]
+// pub use dioxus_mobile as mobile;
 
 pub mod events {
     #[cfg(feature = "html")]