Sfoglia il codice sorgente

Merge pull request #18 from jkelleyrtp/jk/jankfree

wip: polish and publish
Jonathan Kelley 3 anni fa
parent
commit
0ef2f8db4f
100 ha cambiato i file con 678 aggiunte e 932 eliminazioni
  1. 0 1
      .vscode/.gitignore
  2. 4 0
      .vscode/settings.json
  3. 1 0
      .vscode/spellright.dict
  4. 4 2
      Cargo.toml
  5. 93 54
      README.md
  6. 21 8
      docs/main-concepts/02-hello.md
  7. 14 16
      docs/main-concepts/03-rsx.md
  8. 2 2
      docs/main-concepts/04-hooks.md
  9. 2 2
      docs/main-concepts/10-concurrent-mode.md
  10. 3 3
      docs/main-concepts/11-arena-memo.md
  11. 5 5
      docs/main-concepts/12-signals.md
  12. 1 1
      examples/_examples/basic.rs
  13. 1 1
      examples/_examples/calculator.rs
  14. 2 2
      examples/_examples/children.rs
  15. 1 1
      examples/_examples/context.rs
  16. 1 1
      examples/_examples/fragment.rs
  17. 1 1
      examples/_examples/hello.rs
  18. 2 2
      examples/_examples/infer.rs
  19. 3 3
      examples/_examples/input.rs
  20. 1 1
      examples/_examples/jackjill.rs
  21. 1 1
      examples/_examples/jackjillrsx.rs
  22. 1 1
      examples/_examples/landingpage.rs
  23. 1 1
      examples/_examples/landingpage2.rs
  24. 1 1
      examples/_examples/list.rs
  25. 1 1
      examples/_examples/many.rs
  26. 1 1
      examples/_examples/model.rs
  27. 1 1
      examples/_examples/rsxt.rs
  28. 1 1
      examples/_examples/todomvc/main.rs
  29. 1 1
      examples/_examples/weather.rs
  30. 26 24
      examples/async.rs
  31. 0 14
      examples/basic.rs
  32. 22 24
      examples/borrowed.rs
  33. 63 90
      examples/calculator.rs
  34. 2 2
      examples/coroutine.rs
  35. 104 0
      examples/crm.rs
  36. 1 1
      examples/examples/calculator.rs
  37. 2 2
      examples/examples/demo.rs
  38. 1 1
      examples/examples/hifive.rs
  39. 5 6
      examples/file_explorer.rs
  40. 7 7
      examples/framework_benchmark.rs
  41. 1 1
      examples/hydration.rs
  42. 2 3
      examples/manually.rs
  43. 40 43
      examples/model.rs
  44. 1 1
      examples/readme.rs
  45. 11 13
      examples/reducer.rs
  46. 16 16
      examples/reference/antipatterns.rs
  47. 3 3
      examples/reference/basics.rs
  48. 2 2
      examples/reference/children.rs
  49. 18 18
      examples/reference/conditional_rendering.rs
  50. 3 3
      examples/reference/controlled_inputs.rs
  51. 1 1
      examples/reference/custom_elements.rs
  52. 1 1
      examples/reference/empty.rs
  53. 6 6
      examples/reference/errorhandling.rs
  54. 4 4
      examples/reference/fragments.rs
  55. 1 1
      examples/reference/global_css.rs
  56. 2 2
      examples/reference/inline_styles.rs
  57. 1 1
      examples/reference/iterators.rs
  58. 6 6
      examples/reference/listener.rs
  59. 9 9
      examples/reference/memo.rs
  60. 1 1
      examples/reference/noderefs.rs
  61. 1 1
      examples/reference/signals.rs
  62. 5 5
      examples/reference/spreadpattern.rs
  63. 1 1
      examples/reference/statemanagement.rs
  64. 8 3
      examples/reference/suspense.rs
  65. 1 1
      examples/reference/task.rs
  66. 1 1
      examples/reference/testing.rs
  67. 2 2
      examples/reference/tostring.rs
  68. 7 6
      examples/rsx_usage.rs
  69. 7 7
      examples/showcase.rs
  70. 0 112
      examples/slideshow.rs
  71. 2 2
      examples/ssr.rs
  72. 6 6
      examples/tailwind.rs
  73. 0 67
      examples/testbed.rs
  74. 43 46
      examples/todomvc.rs
  75. 4 4
      examples/web_tick.rs
  76. 0 48
      examples/webview.rs
  77. 1 1
      examples/webview_web.rs
  78. 1 1
      notes/Parity.md
  79. 5 5
      notes/SOLVEDPROBLEMS.md
  80. 0 1
      packages/core-macro/examples/fc.rs
  81. 1 1
      packages/core-macro/examples/prop_test.rs
  82. 0 125
      packages/core-macro/examples/rsxt.rs
  83. 2 2
      packages/core-macro/src/ifmt.rs
  84. 4 4
      packages/core-macro/src/lib.rs
  85. 2 2
      packages/core-macro/src/rsx/ambiguous.rs
  86. 1 2
      packages/core-macro/src/rsx/body.rs
  87. 1 1
      packages/core-macro/src/rsx/element.rs
  88. 1 1
      packages/core-macro/src/rsxtemplate.rs
  89. 1 1
      packages/core/.vscode/settings.json
  90. 2 2
      packages/core/README.md
  91. 4 4
      packages/core/benches/jsframework.rs
  92. 6 2
      packages/core/examples/alternative.rs
  93. 8 32
      packages/core/examples/async.rs
  94. 2 2
      packages/core/examples/borrowed.rs
  95. 1 1
      packages/core/examples/contextapi.rs
  96. 1 1
      packages/core/examples/fragment_from_iter.rs
  97. 4 4
      packages/core/examples/jsframework.rs
  98. 3 2
      packages/core/examples/vdom_usage.rs
  99. 5 0
      packages/core/src/bumpframe.rs
  100. 1 2
      packages/core/src/childiter.rs

+ 0 - 1
.vscode/.gitignore

@@ -1 +0,0 @@
-settings.json

+ 4 - 0
.vscode/settings.json

@@ -0,0 +1,4 @@
+{
+  "rust-analyzer.inlayHints.enable": false,
+  "rust-analyzer.cargo.allFeatures": true
+}

+ 1 - 0
.vscode/spellright.dict

@@ -66,3 +66,4 @@ constified
 SegVec
 contentful
 Jank
+noderef

+ 4 - 2
Cargo.toml

@@ -19,7 +19,7 @@ dioxus-mobile = { path = "./packages/mobile", optional = true }
 
 [features]
 # core
-default = ["core", "ssr"]
+default = ["core", "ssr", "web"]
 core = ["macro", "hooks", "html"]
 macro = ["dioxus-core-macro"]
 hooks = ["dioxus-hooks"]
@@ -51,8 +51,10 @@ argh = "0.1.5"
 env_logger = "*"
 async-std = { version = "1.9.0", features = ["attributes"] }
 rand = { version = "0.8.4", features = ["small_rng"] }
-surf = { version = "2.2.0", git = "https://github.com/jkelleyrtp/surf/", branch = "jk/fix-the-wasm" }
 gloo-timers = "0.2.1"
+# surf = { version = "2.3.1", default-features = false, features = [
+#     "wasm-client",
+# ] }
 
 [target.'cfg(target_arch = "wasm32")'.dev-dependencies]
 gloo-timers = "0.2.1"

+ 93 - 54
README.md

@@ -7,38 +7,38 @@
 
 <div align="center">
   <!-- Crates version -->
-  <a href="https://crates.io/crates/async-imap">
-    <img src="https://img.shields.io/crates/v/async-imap.svg?style=flat-square"
+  <a href="https://crates.io/crates/dioxus">
+    <img src="https://img.shields.io/crates/v/dioxus.svg?style=flat-square"
     alt="Crates.io version" />
   </a>
   <!-- Downloads -->
-  <a href="https://crates.io/crates/async-imap">
-    <img src="https://img.shields.io/crates/d/async-imap.svg?style=flat-square"
+  <a href="https://crates.io/crates/dioxus">
+    <img src="https://img.shields.io/crates/d/dioxus.svg?style=flat-square"
       alt="Download" />
   </a>
   <!-- docs.rs docs -->
-  <a href="https://docs.rs/async-imap">
+  <a href="https://docs.rs/dioxus">
     <img src="https://img.shields.io/badge/docs-latest-blue.svg?style=flat-square"
       alt="docs.rs docs" />
   </a>
   <!-- CI -->
-  <a href="https://github.com/async-email/async-imap/actions">
-    <img src="https://github.com/async-email/async-imap/workflows/CI/badge.svg"
+  <a href="https://github.com/jkelleyrtp/dioxus/actions">
+    <img src="https://github.com/jkelleyrtp/dioxus/workflows/CI/badge.svg"
       alt="CI status" />
   </a>
 </div>
 
 <div align="center">
   <h3>
-    <a href="https://docs.rs/async-imap">
+    <a href="https://docs.rs/dioxus">
       API Docs
     </a>
     <span> | </span>
-    <a href="https://docs.rs/async-imap">
+    <a href="https://docs.rs/dioxus">
       Website
     </a>
     <span> | </span>
-    <a href="https://docs.rs/async-imap">
+    <a href="https://docs.rs/dioxus">
       Examples
     </a>
   </h3>
@@ -49,34 +49,21 @@
 Dioxus is a portable, performant, and ergonomic framework for building cross-platform user experiences in Rust.
 
 ```rust
-fn App(cx: Context<()>) -> DomTree {
+static App: FC<()> = |cx, props| {
     let mut count = use_state(cx, || 0);
 
-    cx.render(rsx! {
+    cx.render(rsx!(
         h1 { "High-Five counter: {count}" }
         button { onclick: move |_| count += 1, "Up high!" }
         button { onclick: move |_| count -= 1, "Down low!" }
-    })
+    ))
 };
 ```
 
-Dioxus can be used to deliver webapps, desktop apps, static pages, liveview apps, eventually mobile apps (WIP), and more. At its core, Dioxus is entirely renderer agnostic and has great documentation for creating new renderers for any platform.
+Dioxus can be used to deliver webapps, desktop apps, static sites, liveview apps, mobile apps (WIP), and more. At its core, Dioxus is entirely renderer agnostic and has great documentation for creating new renderers for any platform.
 
 If you know React, then you already know Dioxus.
 
-### **Things you'll love ❤️:**
-
-- Ergonomic design
-- Minimal boilerplate
-- Simple build, test, and deploy
-- Compile-time correct templating
-- Support for fine-grained reactivity
-- Support for html! and rsx! templates
-- SSR, WASM, desktop, and mobile support
-- Support for asynchronous batched rendering
-- Powerful and simple integrated state management
-- Rust! (enums, static types, modules, efficiency)
-
 ### Unique features:
 - Incredible inline documentation. Supports hover and guides for all HTML elements, listeners, and events.
 - Templates are "constified" at compile time. Nodes that don't change will won't be diffed.
@@ -100,8 +87,32 @@ If you know React, then you already know Dioxus.
     <tr>
 </table>
 
-## Explore
+## Examples:
+
+| File Navigator (Desktop)                                         | Bluetooth scanner (Desktop)                                      | TodoMVC (All platforms)                                          | Widget Gallery                                                   |
+| ---------------------------------------------------------------- | ---------------------------------------------------------------- | ---------------------------------------------------------------- | ---------------------------------------------------------------- |
+| ![asd](https://sixtyfps.io/resources/printerdemo_screenshot.png) | ![asd](https://sixtyfps.io/resources/printerdemo_screenshot.png) | ![asd](https://sixtyfps.io/resources/printerdemo_screenshot.png) | ![asd](https://sixtyfps.io/resources/printerdemo_screenshot.png) |
+
+
+
+| E-Commerce Site                                                  | Doxie Documentation Generator                                    | Chatroom                                                         | Widget Gallery                                                   |
+| ---------------------------------------------------------------- | ---------------------------------------------------------------- | ---------------------------------------------------------------- | ---------------------------------------------------------------- |
+| ![asd](https://sixtyfps.io/resources/printerdemo_screenshot.png) | ![asd](https://sixtyfps.io/resources/printerdemo_screenshot.png) | ![asd](https://sixtyfps.io/resources/printerdemo_screenshot.png) | ![asd](https://sixtyfps.io/resources/printerdemo_screenshot.png) |
+
+
+
+| Printer Demo                                                     | Slide Puzzle                                                     | Todo                                                             | Widget Gallery                                                   |
+| ---------------------------------------------------------------- | ---------------------------------------------------------------- | ---------------------------------------------------------------- | ---------------------------------------------------------------- |
+| ![asd](https://sixtyfps.io/resources/printerdemo_screenshot.png) | ![asd](https://sixtyfps.io/resources/printerdemo_screenshot.png) | ![asd](https://sixtyfps.io/resources/printerdemo_screenshot.png) | ![asd](https://sixtyfps.io/resources/printerdemo_screenshot.png) |
 
+
+
+
+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)
@@ -112,15 +123,14 @@ If you know React, then you already know Dioxus.
 - [**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]()
+- [The monoglot startup]() 
+-->
 
 ## Why?
 
@@ -145,7 +155,6 @@ And much more. Dioxus makes Rust apps just as fast to write as React apps, but a
 
 Dioxus is heavily inspired by React, but we want your transition to feel like an upgrade. Dioxus is _most_ of the way there, but missing a few key features. This parity table does not necessarily include important ecosystem crates like code blocks, markdown, resizing hooks, etc.
 
-### Phase 1: The Basics
 
 | Feature                   | Dioxus | React | Notes for Dioxus                                                     |
 | ------------------------- | ------ | ----- | -------------------------------------------------------------------- |
@@ -178,30 +187,60 @@ Dioxus is heavily inspired by React, but we want your transition to feel like an
 | Fine-grained reactivity   | 🛠      | ❓     | Skip diffing for fine-grain updates                                  |
 | Effects                   | 🛠      | ✅     | Run effects after a component has been committed to render           |
 
+- ✅ = implemented and working
+- 🛠 = actively being worked on
+- 👀 = not yet implemented or being worked on
+- ❓ = not sure if will or can implement
 
-### Phase 2: Advanced Toolkits
+## FAQ:
 
-| Feature               | Dioxus | React | Notes for Dioxus                   |
-| --------------------- | ------ | ----- | ---------------------------------- |
-| 1st class router      | 👀      | ✅     | Hook built on top of history       |
-| Assets                | 👀      | ✅     | include css/svg/img url statically |
-| Integrated classnames | 🛠      | ❓     | built-in `classnames`              |
-| Transition            | 👀      | 🛠     | High-level control over suspense   |
-| Animation             | 👀      | ✅     | Spring-style animations            |
-| Native Mobile         | 👀      | ✅     | Render with cacao                  |
-| Native Desktop        | 👀      | ✅     | Render with native desktop         |
-| 3D Renderer           | 👀      | ✅     | react-three-fiber                  |
+### Aren't VDOMs just pure overhead? Why not something like Solid or Svelte?
+Remember: Dioxus is a library - not a compiler like Svelte. Plus, the inner VirtualDOM allows Dioxus to easily port into different runtimes, support SSR, and run remotely in the cloud. VDOMs tend to more ergonomic to work with and feel roughly like natural Rust code. The overhead of Dioxus is **extraordinarily** minimal... sure, there may be some overhead but on an order of magnitude lower than the time required to actually update the page.
 
-### Phase 3: Additional Complexity
 
-| Feature              | Dioxus | React | Notes for Dioxus                     |
-| -------------------- | ------ | ----- | ------------------------------------ |
-| Portal               | ❓      | ✅     | cast elements through tree           |
-| Error/Panic boundary | 👀      | ✅     | catch panics and display custom BSOD |
-| Code-splitting       | 👀      | ✅     | Make bundle smaller/lazy             |
-| LiveView             | 👀      | ❓     | Example for SSR + WASM apps          |
+### Isn't the overhead for interacting with the DOM from WASM too much?
+The overhead layer between WASM and JS APIs is extremely poorly understood. Rust web benchmarks typically suffer from differences in how Rust and JS cache strings. In Dioxus, we solve most of these issues and our JS Framework Benchmark actually beats the WASM Bindgen benchmark in many cases. Compared to a "pure vanilla JS" solution, Dioxus adds less than 5% of overhead and takes advantage of batched DOM manipulation.
 
-- ✅ = implemented and working
-- 🛠 = actively being worked on
-- 👀 = not yet implemented or being worked on
-- ❓ = not sure if will or can implement
+### Aren't WASM binaries too huge to deploy in production?
+WASM binary sizes are another poorly understood characteristic of Rust web apps. 50kb of WASM and 50kb of JS are _not_ made equally. In JS, the code must be downloaded _first_ and _then_ JIT-ted. Just-in-time compiling 50kb of JavaScript takes a while which is why 50kb of JavaScript sounds like a lot! However, with WASM, the code is downloaded and JIT-ted _simultaneously_ through the magic of streaming compilation. By the time the 50kb of Rust is finished downloading, it is already ready to go. Again, Dioxus beats out many benchmarks with time-to-interactivity.
+
+For reference, Dioxus `hello-world` clocks in at around 70kb gzip or 60kb brotli, and Dioxus supports SSR.
+
+### Why hooks? Why not MVC, classes, traits, messages, etc?
+There are plenty Rust Elm-like frameworks in the world - we were not interested in making another! Instead, we borrowed hooks from React. JS and Rust share many structural similarities, so if you're comfortable with React, then you'll be plenty comfortable with Dioxus.
+
+### Why a custom DSL? Why not just pure function calls?
+The `RSX` DSL is _barely_ a DSL. Rustaceans will find the DSL very similar to simply assembling nested structs, but without the syntactical overhead of "Default" everywhere or having to jump through hoops with the builder pattern. Between RSX, HTML, the Raw Factory API, and the NodeBuilder syntax, there's plenty of options to choose from.
+
+### What are the build times like? Why on earth would I choose Rust instead of JS/TS/Elm?
+Dioxus builds as roughly as fast as a complex WebPack-TypeScript site. Compile times will be slower than an equivalent TypeScript site, but not unbearably slow. The WASM compiler backend for Rust is very fast. Iterating on small components is basically instant and larger apps takes a few seconds. In practice, the compiler guarantees of Rust balance out the rebuild times.
+
+### What about Yew/Seed/Sycamore/Dominator/Dodrio/Percy?
+- Yew and Seed use an Elm-like pattern and don't support SSR or any alternate rendering platforms
+- Sycamore and Dominator are more like SolidJS/Svelte, requiring no VDOM but has less naturally-Rusty state management
+- Percy isn't quite mature yet
+- Dodrio is the spiritual predecessor of Dioxus, but is currently an archived research project without the batteries of Dioxus
+
+### How do the mobile and desktop renderers work? Is it Electron?
+Currently, Dioxus uses your device's native WebView library to draw the page. None of your app code is actually running in the WebView thread, so you can access system resources instead of having to go through something like NodeJS. This means your app will use Safari on macOS/iOS, Edge (Chromium) on Windows, and whatever is the default Web Browser for Linux and Android. Because your code is compiled and running natively, performance is not a problem. You will have to use the various "Escape Hatches" to use browser-native APIs (like WebGL) and work around visual differences in how Safari and Chrome render the page.
+
+In the future, we are interested in using Webrenderer to provide a fully native renderer without having to go through the system WebView library. In practice, Dioxus mobile and desktop are great for CRUD-style apps, but the ergonomic cross-platform APIs (GPS, Camera, etc) are not there yet.
+
+### Why NOT Dioxus?
+You shouldn't use Dioxus if:
+- You don't like the React Hooks approach to frontend
+- You need a no-std renderer
+- You want to support browsers where WASM or asm.js are not supported.
+
+
+## License
+
+This project is licensed under the [MIT license].
+
+[MIT license]: https://github.com/tokio-rs/tokio/blob/master/LICENSE
+
+### Contribution
+
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in Pipette by you, shall be licensed as MIT, without any additional
+terms or conditions.

+ 21 - 8
docs/main-concepts/02-hello.md

@@ -78,15 +78,16 @@ Now, let's edit our `main.rs` file:
 ```rust
 use diouxs::prelude::*;
 
+
 fn main() {
-    dioxus::web::start(App)
+    dioxus::web::start(App, |c| c).unwrap();
 }
 
-fn App(cx: Context<()>) -> DomTree {
+static App: FC<()> = |cx, props| {
     cx.render(rsx! {
         div { "Hello, world!" }
     })
-}
+};
 ```
 
 Let's dissect our example a bit.
@@ -97,24 +98,36 @@ This bit of code imports everything from the the `prelude` module. This brings i
 use diouxs::prelude::*;
 ```
 
-This bit of code starts the WASM renderer as a future (JS Promise) and then awaits it. This is very similar to the `ReactDOM.render()` method you use for a React app. We pass in the `App` function as a our app.
+This bit of code starts the WASM renderer as a future (JS Promise) and then awaits it. This is very similar to the `ReactDOM.render()` method you use for a React app. We pass in the `App` function as a our app. The `|c| c` closure provides a way to configure the WebSys app, enabling things like hydration, pre-rendering, and other tweaks. The simplest configuration is just the defaults.
+
+Calling "start" will launch Dioxus on the web's main thread, running `wasm_bindgen_futures::block_on`. It's possible to "launch" the WebSys renderer as an async function - check the documentation for more details.
 
 ```rust
 fn main() {
-    dioxus::web::start(App)
+    dioxus::web::start(App, |c| c).unwrap();
 }
 ```
 
-Finally, our app. Every component in Dioxus is a function that takes in a `Context` object and returns a `VNode`.
+Finally, our app. Every component in Dioxus is a function that takes in `Context` and `Props` and returns an `Option<VNode>`.
 
 ```rust
-fn App(cx: Context<()>) -> DomTree {
+static App: FC<()> = |cx, props| {
     cx.render(rsx! {
         div { "Hello, world!" }
     })
 };
 ```
 
+The closure `FC<()>` syntax is identical to the function syntax, but with lifetimes managed for you. In cases where props need to borrow from their parent, you will need to specify lifetimes using the function syntax:
+
+```rust
+fn App<'a>(cx: Context<'a>, props: &()) -> DomTree<'a> {
+    cx.render(rsx! {
+        div { "Hello, world!" }
+    })    
+}
+```
+
 In React, you'll save data between renders with hooks. However, hooks rely on global variables which make them difficult to integrate in multi-tenant systems like server-rendering. In Dioxus, you are given an explicit `Context` object to control how the component renders and stores data.
 
 Next, we're greeted with the `rsx!` macro. This lets us add a custom DSL for declaratively building the structure of our app. The semantics of this macro are similar to that of JSX and HTML, though with a familiar Rust-y interface. The `html!` macro is also available for writing components with a JSX/HTML syntax.
@@ -135,7 +148,7 @@ If we wanted to golf a bit, we can shrink our hello-world even smaller:
 
 ```rust
 fn main() {
-    dioxus::web::start(|cx| cx.render(diouxs::rsx!( div { "Hello, World!" } ))
+    dioxus::web::start(|cx, _| cx.render(diouxs::rsx!( div { "Hello, World!" } ))
 }
 ```
 

+ 14 - 16
docs/main-concepts/03-rsx.md

@@ -12,15 +12,14 @@ You'll want to write RSX where you can, and in a future release we'll have a too
 
 ```rust
 #[derive(PartialEq, Props)]
-struct ExampleProps { name: &str, pending: bool, count: i32 }
+struct ExampleProps { name: &'static str, pending: bool, count: i32 }
 
-fn Example(cx: Context<ExampleProps> ) -> DomTree {
-    let ExampleProps { name, pending, count } = cx.props;
+static Example: FC<ExampleProps> = |cx, props| {
     cx.render(html! {
         <div>
-            <p> "Hello, {name}!" </p>
-            <p> "Status: {pending}!" </p>
-            <p> "Count {count}!" </p>
+            <p> "Hello, {props.name}!" </p>
+            <p> "Status: {props.pending}!" </p>
+            <p> "Count {props.count}!" </p>
         </div>
     })
 }
@@ -35,13 +34,12 @@ The Dioxus VSCode extension will eventually provide a macro to convert a selecti
 It's also a bit easier on the eyes 🙂 than HTML.
 
 ```rust
-fn Example(cx: Context<ExampleProps>) -> DomTree {
+static Example: FC<ExampleProps> = |cx, props| {
     cx.render(rsx! {
         div {
-            // cx derefs to props so you can access fields directly
-            p {"Hello, {cx.name}!"}
-            p {"Status: {cx.pending}!"}
-            p {"Count {cx.count}!"}
+            p {"Hello, {props.name}!"}
+            p {"Status: {props.pending}!"}
+            p {"Count {props.count}!"}
         }
     })
 }
@@ -60,7 +58,7 @@ Commas are entirely optional, but might be useful to delineate between elements
 The `render` function provides an **extremely efficient** allocator for VNodes and text, so try not to use the `format!` macro in your components. Rust's default `ToString` methods pass through the global allocator, but all text in components is allocated inside a manually-managed Bump arena. To push you in the right direction, all text-based attributes take `std::fmt::Arguments` directly, so you'll want to reach for `format_args!` when the built-in `f-string` interpolation just doesn't cut it.
 
 ```rust
-pub static Example: FC<()> = |cx| {
+pub static Example: FC<()> = |cx, props|{
 
     let text = "example";
 
@@ -113,9 +111,9 @@ pub static Example: FC<()> = |cx| {
                 // rsx! is lazy, and the underlying closures cannot have the same type
                 // Rendering produces the VNode type
                 {match rand::gen_range::<i32>(1..3) {
-                    1 => rsx!(in cx, h1 { "big" })
-                    2 => rsx!(in cx, h2 { "medium" })
-                    _ => rsx!(in cx, h3 { "small" })
+                    1 => rsx!(cx, h1 { "big" })
+                    2 => rsx!(cx, h2 { "medium" })
+                    _ => rsx!(cx, h3 { "small" })
                 }}
 
                 // Optionals
@@ -128,7 +126,7 @@ pub static Example: FC<()> = |cx| {
                 // Duplicating nodes
                 // Clones the nodes by reference, so they are literally identical
                 {{
-                    let node = rsx!(in cx, h1{ "TopNode" });
+                    let node = rsx!(cx, h1{ "TopNode" });
                     (0..10).map(|_| node.clone())
                 }}
 

+ 2 - 2
docs/main-concepts/04-hooks.md

@@ -1,5 +1,5 @@
 ```rust
-fn Example(cx: &mut Context<()>) -> DomTree {
+fn Example<'a>(cx: Context<'a>, props: &()) -> DomTree<'a> {
     let service = use_combubulator(cx);
     let Status { name, pending, count } = service.info();
     html! {
@@ -7,7 +7,7 @@ fn Example(cx: &mut Context<()>) -> DomTree {
             <p> "Hello, {name}!" </p>
             <p> "Status: {pending}!" </p>
             <p> "Count {count}!" </p>
-            <button onclick=|_| service.update()>
+            <button onclick={|_| service.update()}>
                 "Refresh services"
             </button>
         </div>

+ 2 - 2
docs/main-concepts/10-concurrent-mode.md

@@ -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.
     */
     let name: &Result<SomeStructure> = use_fetch_data("http://example.com/json", ())
-                                        .place_holder(|cx| rsx!{<div> "loading..." </div>})
-                                        .delayed_place_holder(1000, |cx| rsx!{ <div> "still loading..." </div>})
+                                        .place_holder(|cx, props|rsx!{<div> "loading..." </div>})
+                                        .delayed_place_holder(1000, |cx, props|rsx!{ <div> "still loading..." </div>})
                                         .await;
 
     match name {

+ 3 - 3
docs/main-concepts/11-arena-memo.md

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

+ 5 - 5
docs/main-concepts/12-signals.md

@@ -96,19 +96,19 @@ Sometimes you want a signal to propagate across your app, either through far-awa
 
 ```rust
 const TITLE: Atom<String> = || "".to_string();
-const Provider: FC<()> = |cx| {
+const Provider: FC<()> = |cx, props|{
     let title = use_signal(&cx, &TITLE);
-    rsx!(in cx, input { value: title })
+    rsx!(cx, input { value: title })
 };
 ```
 
 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
-const Receiver: FC<()> = |cx| {
+const Receiver: FC<()> = |cx, props|{
     let title = use_signal(&cx, &TITLE);
     log::info!("This will only be called once!");
-    rsx!(in cx,
+    rsx!(cx,
         div {
             h1 { "{title}" }
             div {}
@@ -132,7 +132,7 @@ Dioxus automatically understands how to use your signals when mixed with iterato
 
 ```rust
 const DICT: AtomFamily<String, String> = |_| {};
-const List: FC<()> = |cx| {
+const List: FC<()> = |cx, props|{
     let dict = use_signal(&cx, &DICT);
     cx.render(rsx!(
         ul {

+ 1 - 1
examples/_examples/basic.rs

@@ -15,7 +15,7 @@ fn main() {
     wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
 }
 
-static App: FC<()> = |cx| {
+static App: FC<()> = |cx, props| {
     let (state, set_state) = use_state_classic(cx, || 0);
     cx.render(rsx! {
         div {

+ 1 - 1
examples/_examples/calculator.rs

@@ -27,7 +27,7 @@ enum Operator {
     Div,
 }
 
-static App: FC<()> = |cx| {
+static App: FC<()> = |cx, props| {
     let (cur_val, set_cur_val) = use_state_classic(cx, || 0.0_f64);
     let (operator, set_operator) = use_state_classic(cx, || None as Option<Operator>);
     let (display_value, set_display_value) = use_state_classic(cx, || "0".to_string());

+ 2 - 2
examples/_examples/children.rs

@@ -13,7 +13,7 @@ fn main() {
     wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
 }
 
-static App: FC<()> = |cx| {
+static App: FC<()> = |cx, props| {
     cx.render(rsx! {
         Calcier {
             h2 {"abc 1"}
@@ -25,7 +25,7 @@ static App: FC<()> = |cx| {
     })
 };
 
-static Calcier: FC<()> = |cx| {
+static Calcier: FC<()> = |cx, props| {
     cx.render(rsx! {
         div {
             h1 {

+ 1 - 1
examples/_examples/context.rs

@@ -25,7 +25,7 @@ fn main() {
 #[derive(Debug)]
 struct CustomContext([&'static str; 3]);
 
-pub static Example: FC<()> = |cx| {
+pub static Example: FC<()> = |cx, props|{
     cx.use_create_context(|| CustomContext(["Jack", "Jill", "Bob"]));
 
     cx.render(rsx! {

+ 1 - 1
examples/_examples/fragment.rs

@@ -13,7 +13,7 @@ fn main() {
     wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
 }
 
-static App: FC<()> = |cx| {
+static App: FC<()> = |cx, props| {
     cx.render(rsx! {
         h2 { "abc 1" }
         div {

+ 1 - 1
examples/_examples/hello.rs

@@ -13,7 +13,7 @@ fn main() {
     wasm_bindgen_futures::spawn_local(WebsysRenderer::start(Example));
 }
 
-pub static Example: FC<()> = |cx| {
+pub static Example: FC<()> = |cx, props| {
     let nodes = (0..500).map(|f| rsx! (li {"div"}));
     cx.render(rsx! {
         div {

+ 2 - 2
examples/_examples/infer.rs

@@ -14,7 +14,7 @@ fn main() {
 }
 
 // this is a component
-pub static Example: FC<()> = |cx| {
+pub static Example: FC<()> = |cx, props|{
     let (event, set_event) = use_state_classic(cx, || None);
 
     let handler = move |evt| {
@@ -50,7 +50,7 @@ struct ExampleProps {
     name: String,
 }
 
-pub static Example2: FC<ExampleProps> = |cx| {
+pub static Example2: FC<ExampleProps> = |cx, props|{
     cx.render(rsx! {
         div {
             h1 {"hello {cx.name}"}

+ 3 - 3
examples/_examples/input.rs

@@ -12,7 +12,7 @@ fn main() {
     wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
 }
 
-static App: FC<()> = |cx| {
+static App: FC<()> = |cx, props|{
     let (val, set_val) = use_state_classic(cx, || "asd".to_string());
 
     cx.render(rsx! {
@@ -37,7 +37,7 @@ static App: FC<()> = |cx| {
     })
 };
 
-pub static Example: FC<()> = |cx| {
+pub static Example: FC<()> = |cx, props|{
     cx.render(rsx! {
         div { class: "max-w-lg max-w-xs bg-blue-800 shadow-2xl rounded-lg mx-auto text-center py-12 mt-4 rounded-xl"
             div { class: "container py-5 max-w-md mx-auto"
@@ -50,7 +50,7 @@ pub static Example: FC<()> = |cx| {
     })
 };
 
-static UserInput: FC<()> = |cx| {
+static UserInput: FC<()> = |cx, props|{
     let (val, set_val) = use_state_classic(cx, || "asd".to_string());
 
     rsx! { in cx,

+ 1 - 1
examples/_examples/jackjill.rs

@@ -9,7 +9,7 @@ fn main() {
     wasm_bindgen_futures::spawn_local(WebsysRenderer::start(Example))
 }
 
-pub static Example: FC<()> = |cx| {
+pub static Example: FC<()> = |cx, props| {
     let (name, set_name) = use_state_classic(cx, || "...?");
 
     log::debug!("Running component....");

+ 1 - 1
examples/_examples/jackjillrsx.rs

@@ -9,7 +9,7 @@ fn main() {
     wasm_bindgen_futures::spawn_local(WebsysRenderer::start(Example))
 }
 
-pub static Example: FC<()> = |cx| {
+pub static Example: FC<()> = |cx, props| {
     let (name, set_name) = use_state_classic(cx, || "...?");
     cx.render(rsx! {
         section { class: "py-12 px-4 text-center"

+ 1 - 1
examples/_examples/landingpage.rs

@@ -14,7 +14,7 @@ fn main() {
     wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
 }
 
-static App: FC<()> = |cx| {
+static App: FC<()> = |cx, props| {
     let (contents, set_contents) = use_state_classic(cx, || "asd");
 
     cx.render(rsx! {

+ 1 - 1
examples/_examples/landingpage2.rs

@@ -13,7 +13,7 @@ fn main() {
     wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
 }
 
-static App: FC<()> = |cx| {
+static App: FC<()> = |cx, props| {
     let (contents, set_contents) = use_state_classic(cx, || "asd");
 
     cx.render(rsx! {

+ 1 - 1
examples/_examples/list.rs

@@ -26,7 +26,7 @@ pub struct TodoItem {
     pub contents: String,
 }
 
-static App: FC<()> = |cx| {
+static App: FC<()> = |cx, props| {
     let (draft, set_draft) = use_state_classic(cx, || "".to_string());
     let (filter, set_filter) = use_state_classic(cx, || FilterState::All);
     let todos = use_state(cx, || BTreeMap::<uuid::Uuid, TodoItem>::new());

+ 1 - 1
examples/_examples/many.rs

@@ -11,7 +11,7 @@ fn main() {
     wasm_bindgen_futures::spawn_local(WebsysRenderer::start(Example));
 }
 
-pub static Example: FC<()> = |cx| {
+pub static Example: FC<()> = |cx, props| {
     cx.render(rsx! {
         div {
             span {

+ 1 - 1
examples/_examples/model.rs

@@ -31,7 +31,7 @@ fn main() {
     wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
 }
 
-static App: FC<()> = |cx| {
+static App: FC<()> = |cx, props| {
     let state = use_model(&cx, || Calculator::new());
 
     let clear_display = state.display_value.eq("0");

+ 1 - 1
examples/_examples/rsxt.rs

@@ -27,7 +27,7 @@ struct ExampleProps {
     initial_name: &'static str,
 }
 
-pub static Example: FC<ExampleProps> = |cx| {
+pub static Example: FC<ExampleProps> = |cx, props|{
     let name = use_state(cx, move || cx.initial_name);
 
     cx.render(rsx! {

+ 1 - 1
examples/_examples/todomvc/main.rs

@@ -11,7 +11,7 @@ use dioxus_web::{prelude::*, WebsysRenderer};
 static APP_STYLE: &'static str = include_str!("./style.css");
 
 fn main() {
-    wasm_bindgen_futures::spawn_local(WebsysRenderer::start(|cx| {
+    wasm_bindgen_futures::spawn_local(WebsysRenderer::start(|cx, props| {
         cx.render(rsx! {
             div {
                 id: "app"

+ 1 - 1
examples/_examples/weather.rs

@@ -9,7 +9,7 @@ fn main() {
     wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
     console_error_panic_hook::set_once();
 
-    wasm_bindgen_futures::spawn_local(WebsysRenderer::start(|cx| {
+    wasm_bindgen_futures::spawn_local(WebsysRenderer::start(|cx, props| {
         cx.render(html! {
             <div>
                 <div class="flex items-center justify-center flex-col">

+ 26 - 24
examples/async.rs

@@ -1,41 +1,43 @@
-//! Example: README.md showcase
-//!
-//! The example from the README.md
+/*
+This example shows how to use async and loops to implement a coroutine in a component. Coroutines can be controlled via
+the `TaskHandle` object.
+*/
 
 use dioxus::prelude::*;
+use gloo_timers::future::TimeoutFuture;
+
 fn main() {
-    dioxus::desktop::launch(App, |c| c).expect("faield to launch");
+    dioxus::desktop::launch(App, |c| c).unwrap();
 }
 
-pub static App: FC<()> = |cx| {
+pub static App: FC<()> = |cx, _| {
     let count = use_state(cx, || 0);
     let mut direction = use_state(cx, || 1);
 
     let (async_count, dir) = (count.for_async(), *direction);
-    let (task, _result) = use_task(cx, move || async move {
+
+    let (task, _) = use_task(cx, move || async move {
         loop {
-            gloo_timers::future::TimeoutFuture::new(250).await;
+            TimeoutFuture::new(250).await;
             *async_count.get_mut() += dir;
         }
     });
 
-    cx.render(rsx! {
-        div {
-            h1 {"count is {count}"}
-            button {
-                "Stop counting"
-                onclick: move |_| task.stop()
-            }
-            button {
-                "Start counting"
-                onclick: move |_| task.resume()
-            }
-            button {
-                "Switch counting direcion"
-                onclick: move |_| {
-                    direction *= -1;
-                    task.restart();
-                }
+    rsx!(cx, div {
+        h1 {"count is {count}"}
+        button {
+            "Stop counting"
+            onclick: move |_| task.stop()
+        }
+        button {
+            "Start counting"
+            onclick: move |_| task.resume()
+        }
+        button {
+            "Switch counting direcion"
+            onclick: move |_| {
+                direction *= -1;
+                task.restart();
             }
         }
     })

+ 0 - 14
examples/basic.rs

@@ -1,14 +0,0 @@
-use dioxus::prelude::*;
-
-fn main() {
-    let g = dioxus::prelude::LazyNodes::new(move |__cx: NodeFactory| {
-        use dioxus_elements::{GlobalAttributes, SvgAttributes};
-        __cx.element(
-            dioxus_elements::button,
-            [dioxus::events::on::onclick(__cx, move |_| {})],
-            [],
-            [],
-            None,
-        )
-    });
-}

+ 22 - 24
examples/borrowed.rs

@@ -1,20 +1,18 @@
-#![allow(non_snake_case)]
-//! Example: Extremely nested borrowing
-//! -----------------------------------
-//!
-//! Dioxus manages borrow lifetimes for you. This means any child may borrow from its parent. However, it is not possible
-//! to hand out an &mut T to children - all props are consumed by &P, so you'd only get an &&mut T.
-//!
-//! How does it work?
-//!
-//! Dioxus will manually drop closures and props - things that borrow data before the component is ran again. This is done
-//! "bottom up" from the lowest child all the way to the initiating parent. As it traverses each listener and prop, the
-//! drop implementation is manually called, freeing any memory and ensuring that memory is not leaked.
-//!
-//! We cannot drop from the parent to the children - if the drop implementation modifies the data, downstream references
-//! might be broken since we take an &mut T and and &T to the data. Instead, we work bottom up, making sure to remove any
-//! potential references to the data before finally giving out an &mut T. This prevents us from mutably aliasing the data,
-//! and is proven to be safe with MIRI.
+/*
+Dioxus manages borrow lifetimes for you. This means any child may borrow from its parent. However, it is not possible
+to hand out an &mut T to children - all props are consumed by &P, so you'd only get an &&mut T.
+
+How does it work?
+
+Dioxus will manually drop closures and props - things that borrow data before the component is ran again. This is done
+"bottom up" from the lowest child all the way to the initiating parent. As it traverses each listener and prop, the
+drop implementation is manually called, freeing any memory and ensuring that memory is not leaked.
+
+We cannot drop from the parent to the children - if the drop implementation modifies the data, downstream references
+might be broken since we take an &mut T and and &T to the data. Instead, we work bottom up, making sure to remove any
+potential references to the data before finally giving out an &mut T. This prevents us from mutably aliasing the data,
+and is proven to be safe with MIRI.
+*/
 
 use dioxus::prelude::*;
 
@@ -22,7 +20,7 @@ fn main() {
     dioxus::desktop::launch(App, |c| c);
 }
 
-fn App<'a>(cx: Context<'a, ()>) -> DomTree<'a> {
+fn App<'a>(cx: Context<'a>, props: &()) -> DomTree<'a> {
     let text: &'a mut Vec<String> = cx.use_hook(|_| vec![String::from("abc=def")], |f| f, |_| {});
 
     let first = text.get_mut(0).unwrap();
@@ -45,8 +43,8 @@ impl<'a> Drop for C1Props<'a> {
     fn drop(&mut self) {}
 }
 
-fn Child1<'a>(cx: Context<'a, C1Props>) -> DomTree<'a> {
-    let (left, right) = cx.text.split_once("=").unwrap();
+fn Child1<'a>(cx: Context<'a>, props: &'a C1Props) -> DomTree<'a> {
+    let (left, right) = props.text.split_once("=").unwrap();
 
     cx.render(rsx! {
         div {
@@ -66,10 +64,10 @@ impl<'a> Drop for C2Props<'a> {
     }
 }
 
-fn Child2<'a>(cx: Context<'a, C2Props>) -> DomTree<'a> {
+fn Child2<'a>(cx: Context<'a>, props: &'a C2Props) -> DomTree<'a> {
     cx.render(rsx! {
         Child3 {
-            text: cx.text
+            text: props.text
         }
     })
 }
@@ -79,8 +77,8 @@ struct C3Props<'a> {
     text: &'a str,
 }
 
-fn Child3<'a>(cx: Context<'a, C3Props>) -> DomTree<'a> {
+fn Child3<'a>(cx: Context<'a>, props: &C3Props) -> DomTree<'a> {
     cx.render(rsx! {
-        div { "{cx.text}"}
+        div { "{props.text}"}
     })
 }

+ 63 - 90
examples/calculator.rs

@@ -1,44 +1,36 @@
-//! Example: Calculator
-//! -------------------------
-
-// use dioxus::events::on::*;
-// use dioxus::prelude::*;
-
-fn main() {
-    env_logger::init();
-    dioxus::desktop::launch(App, |cfg| cfg);
-}
+/*
+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.
+*/
 
 use dioxus::events::on::*;
 use dioxus::prelude::*;
 
-enum Operator {
-    Add,
-    Sub,
-    Mul,
-    Div,
+fn main() {
+    dioxus::desktop::launch(APP, |cfg| cfg).unwrap();
 }
 
-const App: FC<()> = |cx| {
+const APP: FC<()> = |cx, _| {
     let cur_val = use_state(cx, || 0.0_f64);
-    let operator = use_state(cx, || None as Option<Operator>);
-    let display_value = use_state(cx, || "".to_string());
+    let operator = use_state(cx, || None as Option<&'static str>);
+    let display_value = use_state(cx, || String::from(""));
 
     let clear_display = display_value == "0";
     let clear_text = if clear_display { "C" } else { "AC" };
 
-    let input_digit = move |num: u8| display_value.get_mut().push_str(num.to_string().as_str());
+    let input_digit = move |num: u8| display_value.modify().push_str(num.to_string().as_str());
 
-    let input_dot = move || display_value.get_mut().push_str(".");
+    let input_dot = move || display_value.modify().push_str(".");
 
     let perform_operation = move || {
         if let Some(op) = operator.as_ref() {
             let rhs = display_value.parse::<f64>().unwrap();
-            let new_val = match op {
-                Operator::Add => *cur_val + rhs,
-                Operator::Sub => *cur_val - rhs,
-                Operator::Mul => *cur_val * rhs,
-                Operator::Div => *cur_val / rhs,
+            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());
@@ -65,51 +57,54 @@ const App: FC<()> = |cx| {
     };
 
     let keydownhandler = move |evt: KeyboardEvent| 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.get_mut().pop();
+                display_value.modify().pop();
             }
         }
-        KeyCode::_0 => input_digit(0),
-        KeyCode::_1 => input_digit(1),
-        KeyCode::_2 => input_digit(2),
-        KeyCode::_3 => input_digit(3),
-        KeyCode::_4 => input_digit(4),
-        KeyCode::_5 => input_digit(5),
-        KeyCode::_6 => input_digit(6),
-        KeyCode::_7 => input_digit(7),
-        KeyCode::_8 => input_digit(8),
-        KeyCode::_9 => input_digit(9),
-        KeyCode::Add => operator.set(Some(Operator::Add)),
-        KeyCode::Subtract => operator.set(Some(Operator::Sub)),
-        KeyCode::Divide => operator.set(Some(Operator::Div)),
-        KeyCode::Multiply => operator.set(Some(Operator::Mul)),
         _ => {}
     };
 
-    cx.render(rsx! {
-        div { class: "calculator", onkeydown: {keydownhandler}
-            div { class: "input-keys"
-                div { class: "function-keys"
-                    CalculatorKey { name: "key-clear", onclick: {clear_key} "{clear_text}" }
-                    CalculatorKey { name: "key-sign", onclick: {toggle_sign}, "±"}
-                    CalculatorKey { name: "key-percent", onclick: {toggle_percent} "%"}
-                }
-                div { class: "digit-keys"
-                    CalculatorKey { name: "key-0", onclick: move |_| input_digit(0), "0" }
-                    CalculatorKey { name: "key-dot", onclick: move |_|  input_dot(), "●" }
-
-                    {(1..9).map(move |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(Operator::Div)) "÷" }
-                    CalculatorKey { name: "key-multiply", onclick: move |_| operator.set(Some(Operator::Mul)) "×" }
-                    CalculatorKey { name: "key-subtract", onclick: move |_| operator.set(Some(Operator::Sub)) "−" }
-                    CalculatorKey { name: "key-add", onclick: move |_| operator.set(Some(Operator::Add)) "+" }
-                    CalculatorKey { name: "key-equals", onclick: move |_| perform_operation() "=" }
-                }
+    use separator::Separatable;
+    let formatted_display = cur_val.separated_string();
+
+    rsx!(cx, div {
+        class: "calculator", onkeydown: {keydownhandler}
+        div { class: "calculator-display", "{formatted_display}" }
+        div { class: "input-keys"
+            div { class: "function-keys"
+                CalculatorKey { name: "key-clear", onclick: {clear_key} "{clear_text}" }
+                CalculatorKey { name: "key-sign", onclick: {toggle_sign}, "±"}
+                CalculatorKey { name: "key-percent", onclick: {toggle_percent} "%"}
+            }
+            div { class: "digit-keys"
+                CalculatorKey { name: "key-0", onclick: move |_| input_digit(0), "0" }
+                CalculatorKey { name: "key-dot", onclick: move |_| input_dot(), "●" }
+
+                {(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 |_| perform_operation() "=" }
             }
         }
     })
@@ -117,36 +112,14 @@ const App: FC<()> = |cx| {
 
 #[derive(Props)]
 struct CalculatorKeyProps<'a> {
-    /// Name!
     name: &'static str,
-
-    /// Click!
     onclick: &'a dyn Fn(MouseEvent),
 }
 
-fn CalculatorKey<'a, 'r>(cx: Context<'a, CalculatorKeyProps<'r>>) -> DomTree<'a> {
-    cx.render(rsx! {
-        button {
-            class: "calculator-key {cx.name}"
-            onclick: {cx.onclick}
-            {cx.children()}
-        }
-    })
-}
-
-#[derive(Props, PartialEq)]
-struct CalculatorDisplayProps {
-    val: f64,
-}
-
-fn CalculatorDisplay(cx: Context<CalculatorDisplayProps>) -> DomTree {
-    use separator::Separatable;
-    // Todo, add float support to the num-format crate
-    let formatted = cx.val.separated_string();
-    // TODO: make it autoscaling with css
-    cx.render(rsx! {
-        div { class: "calculator-display"
-            "{formatted}"
-        }
+fn CalculatorKey<'a>(cx: Context<'a>, props: &'a CalculatorKeyProps) -> DomTree<'a> {
+    rsx!(cx, button {
+        class: "calculator-key {props.name}"
+        onclick: {props.onclick}
+        {cx.children()}
     })
 }

+ 2 - 2
examples/coroutine.rs

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

+ 104 - 0
examples/crm.rs

@@ -0,0 +1,104 @@
+/*
+Tiny CRM: A port of the Yew CRM example to Dioxus.
+*/
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus::web::launch(App, |c| c);
+}
+enum Scene {
+    ClientsList,
+    NewClientForm,
+    Settings,
+}
+
+#[derive(Clone, Debug, Default)]
+pub struct Client {
+    pub first_name: String,
+    pub last_name: String,
+    pub description: String,
+}
+
+static App: FC<()> = |cx, _| {
+    let scene = use_state(cx, || Scene::ClientsList);
+    let clients = use_ref(cx, || vec![] as Vec<Client>);
+
+    let firstname = use_state(cx, || String::new());
+    let lastname = use_state(cx, || String::new());
+    let description = use_state(cx, || String::new());
+
+    let scene = match *scene {
+        Scene::ClientsList => {
+            rsx!(cx, div { class: "crm"
+                h2 { "List of clients" margin_bottom: "10px" }
+                div { class: "clients" margin_left: "10px"
+                    {clients.read().iter().map(|client| rsx!(
+                        div { class: "client" style: "margin-bottom: 50px"
+                            p { "First Name: {client.first_name}" }
+                            p { "Last Name: {client.last_name}" }
+                            p {"Description: {client.description}"}
+                        })
+                    )}
+                }
+                button { class: "pure-button pure-button-primary" onclick: move |_| scene.set(Scene::NewClientForm), "Add New" }
+                button { class: "pure-button" onclick: move |_| scene.set(Scene::Settings), "Settings" }
+            })
+        }
+        Scene::NewClientForm => {
+            let add_new = move |_| {
+                clients.write().push(Client {
+                    description: (*description).clone(),
+                    first_name: (*firstname).clone(),
+                    last_name: (*lastname).clone(),
+                });
+                description.set(String::new());
+                firstname.set(String::new());
+                lastname.set(String::new());
+            };
+            rsx!(cx, div { class: "crm"
+                h2 {"Add new client" margin_bottom: "10px" }
+                form { class: "pure-form"
+                    input { class: "new-client firstname" placeholder: "First name" value: "{firstname}"
+                        oninput: move |e| firstname.set(e.value())
+                    }
+                    input { class: "new-client lastname" placeholder: "Last name" value: "{lastname}"
+                        oninput: move |e| lastname.set(e.value())
+                    }
+                    textarea { class: "new-client description" placeholder: "Description" value: "{description}"
+                        oninput: move |e| description.set(e.value())
+                    }
+                }
+                button { class: "pure-button pure-button-primary", onclick: {add_new}, "Add New" }
+                button { class: "pure-button", onclick: move |_| scene.set(Scene::ClientsList), "Go Back" }
+            })
+        }
+        Scene::Settings => {
+            rsx!(cx, div {
+                h2 {"Settings" margin_bottom: "10px" }
+                button {
+                    background: "rgb(202, 60, 60)"
+                    class: "pure-button pure-button-primary"
+                    onclick: move |_| clients.write().clear(),
+                    "Remove all clients"
+                }
+                button {
+                    class: "pure-button pure-button-primary"
+                    onclick: move |_| scene.set(Scene::ClientsList),
+                    "Go Back"
+                }
+            })
+        }
+    };
+
+    rsx!(cx, body {
+        link {
+            rel: "stylesheet"
+            href: "https://unpkg.com/purecss@2.0.6/build/pure-min.css"
+            integrity: "sha384-Uu6IeWbM+gzNVXJcM9XV3SohHtmWE+3VGi496jvgX1jyvDTXfdK+rfZc8C1Aehk5"
+            crossorigin: "anonymous"
+        }
+        margin_left: "35%"
+        h1 {"Dioxus CRM Example"}
+        {scene}
+    })
+};

+ 1 - 1
examples/examples/calculator.rs

@@ -19,7 +19,7 @@ fn main() {
     .expect("Webview finished");
 }
 
-static App: FC<()> = |cx| {
+static App: FC<()> = |cx, props| {
     let state = use_model(&cx, || Calculator::new());
 
     let clear_display = state.display_value.eq("0");

+ 2 - 2
examples/examples/demo.rs

@@ -17,7 +17,7 @@ fn main() {
     .expect("Webview finished");
 }
 
-// pub static Example: FC<()> = |cx| {
+// pub static Example: FC<()> = |cx, props|{
 //     cx.render(html! {
 //         <div>
 //         <svg class="octicon octicon-star v-align-text-bottom"
@@ -36,7 +36,7 @@ fn main() {
 //         </div>
 //     })
 // };
-pub static Example: FC<()> = |cx| {
+pub static Example: FC<()> = |cx, props| {
     cx.render(rsx! {
         div  {
             class: "flex items-center justify-center flex-col"

+ 1 - 1
examples/examples/hifive.rs

@@ -17,7 +17,7 @@ fn main() {
     .expect("Webview finished");
 }
 
-static App: FC<()> = |cx| {
+static App: FC<()> = |cx, props| {
     let hifives = use_model(&cx, || 0);
     cx.render(rsx! {
         div {

+ 5 - 6
examples/file_explorer.rs

@@ -7,7 +7,6 @@
 
 use dioxus::desktop::wry::application::dpi::LogicalSize;
 use dioxus::prelude::*;
-use std::fs::{self, DirEntry};
 
 fn main() {
     env_logger::init();
@@ -20,12 +19,12 @@ fn main() {
     .unwrap();
 }
 
-static App: FC<()> = |cx| {
+static App: FC<()> = |cx, props| {
     let files = use_state(cx, || Files::new());
 
     let file_list = files.path_names.iter().enumerate().map(|(dir_id, path)| {
         rsx! (
-            li { a {"{path}", onclick: move |_| files.get_mut().enter_dir(dir_id), href: "#"} }
+            li { a {"{path}", onclick: move |_| files.modify().enter_dir(dir_id), href: "#"} }
         )
     });
 
@@ -33,7 +32,7 @@ static App: FC<()> = |cx| {
         rsx! {
             div {
                 code {"{err}"}
-                button {"x", onclick: move |_| files.get_mut().clear_err() }
+                button {"x", onclick: move |_| files.modify().clear_err() }
             }
         }
     });
@@ -43,7 +42,7 @@ static App: FC<()> = |cx| {
         div {
             h1 {"Files: "}
             h3 {"Cur dir: {cur}"}
-            button { "go up", onclick: move |_| files.get_mut().go_up() }
+            button { "go up", onclick: move |_| files.modify().go_up() }
             ol { {file_list} }
             {err_disp}
         }
@@ -73,7 +72,7 @@ impl Files {
 
     fn reload_path_list(&mut self) {
         let cur_path = self.path_stack.last().unwrap();
-        let paths = match fs::read_dir(cur_path) {
+        let paths = match std::fs::read_dir(cur_path) {
             Ok(e) => e,
             Err(err) => {
                 let err = format!("An error occured: {:?}", err);

+ 7 - 7
examples/framework_benchmark.rs

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

+ 1 - 1
examples/hydration.rs

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

+ 2 - 3
examples/manually.rs

@@ -6,7 +6,6 @@ fn main() {
     // .. should result in an "invalid node tree"
     let edits = vec![
         CreateElement { tag: "div", id: 0 },
-        // CreatePlaceholder { id: 1 },
         CreateElement { tag: "h1", id: 2 },
         CreateTextNode {
             text: "hello world",
@@ -15,9 +14,9 @@ fn main() {
         AppendChildren { many: 1 },
         AppendChildren { many: 1 },
         AppendChildren { many: 1 },
-        // ReplaceWith { many: 1 },
     ];
+
     dioxus_desktop::WebviewRenderer::run_with_edits(App, (), |c| c, Some(edits)).expect("failed");
 }
 
-const App: FC<()> = |cx| todo!();
+const App: FC<()> = |cx, props| todo!();

+ 40 - 43
examples/model.rs

@@ -32,41 +32,39 @@ fn main() {
     .expect("failed to launch dioxus app");
 }
 
-static App: FC<()> = |cx| {
-    let state = use_state(cx, || Calculator::new());
+static App: FC<()> = |cx, props| {
+    let state = use_ref(cx, || Calculator::new());
 
-    let clear_display = state.display_value.eq("0");
+    let clear_display = state.read().display_value.eq("0");
     let clear_text = if clear_display { "C" } else { "AC" };
-    let formatted = state.formatted_display();
+    let formatted = state.read().formatted_display();
 
-    cx.render(rsx! {
-        div { id: "wrapper"
-            div { class: "app", style { "{STYLE}" }
-                div { class: "calculator", onkeypress: move |evt| state.get_mut().handle_keydown(evt),
-                    div { class: "calculator-display", "{formatted}"}
-                    div { class: "calculator-keypad"
-                        div { class: "input-keys"
-                            div { class: "function-keys"
-                                CalculatorKey { name: "key-clear", onclick: move |_| state.get_mut().clear_display(), "{clear_text}" }
-                                CalculatorKey { name: "key-sign", onclick: move |_| state.get_mut().toggle_sign(), "±"}
-                                CalculatorKey { name: "key-percent", onclick: move |_| state.get_mut().toggle_percent(), "%"}
-                            }
-                            div { class: "digit-keys"
-                                CalculatorKey { name: "key-0", onclick: move |_| state.get_mut().input_digit(0), "0" }
-                                CalculatorKey { name: "key-dot", onclick: move |_|  state.get_mut().input_dot(), "●" }
-                                {(1..10).map(move |k| rsx!{
-                                    CalculatorKey { key: "{k}", name: "key-{k}", onclick: move |_|  state.get_mut().input_digit(k), "{k}" }
-                                })}
-                            }
+    rsx!(cx, div { id: "wrapper"
+        div { class: "app", style { "{STYLE}" }
+            div { class: "calculator", onkeypress: move |evt| state.write().handle_keydown(evt),
+                div { class: "calculator-display", "{formatted}"}
+                div { class: "calculator-keypad"
+                    div { class: "input-keys"
+                        div { class: "function-keys"
+                            CalculatorKey { name: "key-clear", onclick: move |_| state.write().clear_display(), "{clear_text}" }
+                            CalculatorKey { name: "key-sign", onclick: move |_| state.write().toggle_sign(), "±"}
+                            CalculatorKey { name: "key-percent", onclick: move |_| state.write().toggle_percent(), "%"}
                         }
-                        div { class: "operator-keys"
-                            CalculatorKey { name:"key-divide", onclick: move |_| state.get_mut().set_operator(Operator::Div), "÷" }
-                            CalculatorKey { name:"key-multiply", onclick: move |_| state.get_mut().set_operator(Operator::Mul), "×" }
-                            CalculatorKey { name:"key-subtract", onclick: move |_| state.get_mut().set_operator(Operator::Sub), "−" }
-                            CalculatorKey { name:"key-add", onclick: move |_| state.get_mut().set_operator(Operator::Add), "+" }
-                            CalculatorKey { name:"key-equals", onclick: move |_| state.get_mut().perform_operation(), "=" }
+                        div { class: "digit-keys"
+                            CalculatorKey { name: "key-0", onclick: move |_| state.write().input_digit(0), "0" }
+                            CalculatorKey { name: "key-dot", onclick: move |_|  state.write().input_dot(), "●" }
+                            {(1..10).map(move |k| rsx!{
+                                CalculatorKey { key: "{k}", name: "key-{k}", onclick: move |_|  state.write().input_digit(k), "{k}" }
+                            })}
                         }
                     }
+                    div { class: "operator-keys"
+                        CalculatorKey { name:"key-divide", onclick: move |_| state.write().set_operator(Operator::Div), "÷" }
+                        CalculatorKey { name:"key-multiply", onclick: move |_| state.write().set_operator(Operator::Mul), "×" }
+                        CalculatorKey { name:"key-subtract", onclick: move |_| state.write().set_operator(Operator::Sub), "−" }
+                        CalculatorKey { name:"key-add", onclick: move |_| state.write().set_operator(Operator::Add), "+" }
+                        CalculatorKey { name:"key-equals", onclick: move |_| state.write().perform_operation(), "=" }
+                    }
                 }
             }
         }
@@ -79,17 +77,16 @@ struct CalculatorKeyProps<'a> {
     onclick: &'a dyn Fn(MouseEvent),
 }
 
-fn CalculatorKey<'a, 'r>(cx: Context<'a, CalculatorKeyProps<'r>>) -> DomTree<'a> {
+fn CalculatorKey<'a, 'r>(cx: Context<'a>, props: &'a CalculatorKeyProps) -> DomTree<'a> {
     cx.render(rsx! {
         button {
-            class: "calculator-key {cx.name}"
-            onclick: {cx.onclick}
+            class: "calculator-key {props.name}"
+            onclick: {props.onclick}
             {cx.children()}
         }
     })
 }
 
-#[derive(Clone)]
 struct Calculator {
     display_value: String,
     operator: Option<Operator>,
@@ -174,16 +171,16 @@ impl Calculator {
     fn handle_keydown(&mut self, evt: KeyboardEvent) {
         match evt.key_code() {
             KeyCode::Backspace => self.backspace(),
-            KeyCode::_0 => self.input_digit(0),
-            KeyCode::_1 => self.input_digit(1),
-            KeyCode::_2 => self.input_digit(2),
-            KeyCode::_3 => self.input_digit(3),
-            KeyCode::_4 => self.input_digit(4),
-            KeyCode::_5 => self.input_digit(5),
-            KeyCode::_6 => self.input_digit(6),
-            KeyCode::_7 => self.input_digit(7),
-            KeyCode::_8 => self.input_digit(8),
-            KeyCode::_9 => self.input_digit(9),
+            KeyCode::Num0 => self.input_digit(0),
+            KeyCode::Num1 => self.input_digit(1),
+            KeyCode::Num2 => self.input_digit(2),
+            KeyCode::Num3 => self.input_digit(3),
+            KeyCode::Num4 => self.input_digit(4),
+            KeyCode::Num5 => self.input_digit(5),
+            KeyCode::Num6 => self.input_digit(6),
+            KeyCode::Num7 => self.input_digit(7),
+            KeyCode::Num8 => self.input_digit(8),
+            KeyCode::Num9 => self.input_digit(9),
             KeyCode::Add => self.operator = Some(Operator::Add),
             KeyCode::Subtract => self.operator = Some(Operator::Sub),
             KeyCode::Divide => self.operator = Some(Operator::Div),

+ 1 - 1
examples/readme.rs

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

+ 11 - 13
examples/reducer.rs

@@ -11,23 +11,21 @@ fn main() {
     dioxus::desktop::launch(App, |c| c);
 }
 
-pub static App: FC<()> = |cx| {
+pub static App: FC<()> = |cx, _| {
     let state = use_state(cx, PlayerState::new);
 
     let is_playing = state.is_playing();
 
-    cx.render(rsx! {
-        div {
-            h1 {"Select an option"}
-            h3 {"The radio is... {is_playing}!"}
-            button {
-                "Pause"
-                onclick: move |_| state.get_mut().reduce(PlayerAction::Pause)
-            }
-            button {
-                "Play"
-                onclick: move |_| state.get_mut().reduce(PlayerAction::Play)
-            }
+    rsx!(cx, div {
+        h1 {"Select an option"}
+        h3 {"The radio is... {is_playing}!"}
+        button {
+            "Pause"
+            onclick: move |_| state.modify().reduce(PlayerAction::Pause)
+        }
+        button {
+            "Play"
+            onclick: move |_| state.modify().reduce(PlayerAction::Play)
         }
     })
 };

+ 16 - 16
examples/reference/antipatterns.rs

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

+ 3 - 3
examples/reference/basics.rs

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

+ 2 - 2
examples/reference/children.rs

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

+ 18 - 18
examples/reference/conditional_rendering.rs

@@ -16,10 +16,10 @@ use dioxus::prelude::*;
 pub struct MyProps {
     should_show: bool,
 }
-pub static Example0: FC<MyProps> = |cx| {
+pub static Example0: FC<MyProps> = |cx, props| {
     cx.render(rsx! {
         div {
-            {cx.should_show.then(|| rsx!{
+            {props.should_show.then(|| rsx!{
                 h1 { "showing the title!" }
             })}
         }
@@ -34,32 +34,32 @@ pub static Example0: FC<MyProps> = |cx| {
 // which will do essentially the same thing as `cx.render`.
 //
 // In short:
-// `rsx!(in cx, ...)` is shorthand for `cx.render(rsx!(...))`
+// `rsx!(cx, ...)` is shorthand for `cx.render(rsx!(...))`
 #[derive(PartialEq, Props)]
 pub struct MyProps1 {
     should_show: bool,
 }
-pub static Example1: FC<MyProps1> = |cx| {
+pub static Example1: FC<MyProps1> = |cx, props| {
     cx.render(rsx! {
         div {
             // With matching
-            {match cx.should_show {
+            {match props.should_show {
                 true => cx.render(rsx!(div {"it is true!"})),
-                false => rsx!(in cx, div {"it is false!"}),
+                false => rsx!(cx, div {"it is false!"}),
             }}
 
             // or with just regular conditions
-            {if cx.should_show {
-                rsx!(in cx, div {"it is true!"})
+            {if props.should_show {
+                rsx!(cx, div {"it is true!"})
             } else {
-                rsx!(in cx, div {"it is false!"})
+                rsx!(cx, div {"it is false!"})
             }}
 
             // or with optional chaining
             {
-                cx.should_show
-                .then(|| rsx!(in cx, div {"it is false!"}))
-                .unwrap_or_else(|| rsx!(in cx, div {"it is false!"}))
+                props.should_show
+                .then(|| rsx!(cx, div {"it is false!"}))
+                .unwrap_or_else(|| rsx!(cx, div {"it is false!"}))
             }
         }
     })
@@ -77,19 +77,19 @@ pub enum Color {
 pub struct MyProps2 {
     color: Color,
 }
-pub static Example2: FC<MyProps2> = |cx| {
+pub static Example2: FC<MyProps2> = |cx, props| {
     cx.render(rsx! {
         div {
-            {match cx.color {
-                Color::Green => rsx!(in cx, div {"it is Green!"}),
-                Color::Yellow => rsx!(in cx, div {"it is Yellow!"}),
-                Color::Red => rsx!(in cx, div {"it is Red!"}),
+            {match props.color {
+                Color::Green => rsx!(cx, div {"it is Green!"}),
+                Color::Yellow => rsx!(cx, div {"it is Yellow!"}),
+                Color::Red => rsx!(cx, div {"it is Red!"}),
             }}
         }
     })
 };
 
-pub static Example: FC<()> = |cx| {
+pub static Example: FC<()> = |cx, props| {
     let should_show = use_state(cx, || false);
     let mut color_index = use_state(cx, || 0);
     let color = match *color_index % 2 {

+ 3 - 3
examples/reference/controlled_inputs.rs

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

+ 1 - 1
examples/reference/custom_elements.rs

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

+ 1 - 1
examples/reference/empty.rs

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

+ 6 - 6
examples/reference/errorhandling.rs

@@ -23,14 +23,14 @@ fn main() {}
 /// 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.
 /// This is pretty flimsy.
-static App: FC<()> = |cx| {
+static App: FC<()> = |cx, props| {
     let data = get_data().unwrap();
     cx.render(rsx!( div { "{data}" } ))
 };
 
 /// 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
-static App1: FC<()> = |cx| {
+static App1: FC<()> = |cx, props| {
     let data = match get_data() {
         Some(data) => data,
         None => return None,
@@ -46,7 +46,7 @@ static App1: FC<()> = |cx| {
 /// a user is logged in.
 ///
 /// Dioxus will throw an error in the console if the None-path is ever taken.
-static App2: FC<()> = |cx| {
+static App2: FC<()> = |cx, props| {
     let data = get_data()?;
     cx.render(rsx!( div { "{data}" } ))
 };
@@ -54,14 +54,14 @@ static App2: FC<()> = |cx| {
 /// This is top-tier error handling since it displays a failure state.
 ///
 /// However, the error is lacking in context.
-static App3: FC<()> = |cx| match get_data() {
+static App3: FC<()> = |cx, props| match get_data() {
     Some(data) => cx.render(rsx!( div { "{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
 /// a Result<T, V> into an Option<T> and lets you
-static App4: FC<()> = |cx| {
+static App4: FC<()> = |cx, props| {
     let data = get_data_err().ok()?;
     cx.render(rsx!( div { "{data}" } ))
 };
@@ -69,7 +69,7 @@ static App4: FC<()> = |cx| {
 /// 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
-static App5: FC<()> = |cx| match get_data_err() {
+static App5: FC<()> = |cx, props| match get_data_err() {
     Ok(data) => cx.render(rsx!( div { "{data}" } )),
     Err(c) => cx.render(rsx!( div { "Failed to load data: {c}" } )),
 };

+ 4 - 4
examples/reference/fragments.rs

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

+ 1 - 1
examples/reference/global_css.rs

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

+ 2 - 2
examples/reference/inline_styles.rs

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

+ 1 - 1
examples/reference/iterators.rs

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

+ 6 - 6
examples/reference/listener.rs

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

+ 9 - 9
examples/reference/memo.rs

@@ -21,7 +21,7 @@ use dioxus::prelude::*;
 
 // By default, components with no props are always memoized.
 // A props of () is considered empty.
-pub static Example: FC<()> = |cx| {
+pub static Example: FC<()> = |cx, props| {
     cx.render(rsx! {
         div { "100% memoized!" }
     })
@@ -35,9 +35,9 @@ pub struct MyProps1 {
     name: String,
 }
 
-pub static Example1: FC<MyProps1> = |cx| {
+pub static Example1: FC<MyProps1> = |cx, props| {
     cx.render(rsx! {
-        div { "100% memoized! {cx.name}" }
+        div { "100% memoized! {props.name}" }
     })
 };
 
@@ -49,9 +49,9 @@ pub struct MyProps2 {
     name: std::rc::Rc<str>,
 }
 
-pub static Example2: FC<MyProps2> = |cx| {
+pub static Example2: FC<MyProps2> = |cx, props| {
     cx.render(rsx! {
-        div { "100% memoized! {cx.name}" }
+        div { "100% memoized! {props.name}" }
     })
 };
 
@@ -63,9 +63,9 @@ pub struct MyProps3<'a> {
 // We need to manually specify a lifetime that ensures props and scope (the component's state) share the same lifetime.
 // Using the `pub static Example: FC<()>` pattern _will_ specify a lifetime, but that lifetime will be static which might
 // not exactly be what you want
-fn Example3<'a>(cx: Context<'a, MyProps3<'a>>) -> DomTree {
+fn Example3<'a>(cx: Context<'a>, props: &'a MyProps3) -> DomTree<'a> {
     cx.render(rsx! {
-        div { "Not memoized! {cx.name}" }
+        div { "Not memoized! {props.name}" }
     })
 }
 
@@ -77,8 +77,8 @@ pub struct MyProps4<'a> {
 }
 
 // We need to manually specify a lifetime that ensures props and scope (the component's state) share the same lifetime.
-fn Example4<'a>(cx: Context<'a, MyProps4<'a>>) -> DomTree {
+fn Example4<'a>(cx: Context<'a>, props: &'a MyProps4) -> DomTree<'a> {
     cx.render(rsx! {
-        div { "Not memoized!", onclick: move |_| (cx.onhandle)() }
+        div { "Not memoized!", onclick: move |_| (props.onhandle)() }
     })
 }

+ 1 - 1
examples/reference/noderefs.rs

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

+ 1 - 1
examples/reference/signals.rs

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

+ 5 - 5
examples/reference/spreadpattern.rs

@@ -9,7 +9,7 @@
 
 use dioxus::prelude::*;
 
-pub static Example: FC<()> = |cx| {
+pub static Example: FC<()> = |cx, props| {
     let props = MyProps {
         count: 0,
         live: true,
@@ -27,12 +27,12 @@ pub struct MyProps {
     name: &'static str,
 }
 
-pub static Example1: FC<MyProps> = |cx| {
+pub static Example1: FC<MyProps> = |cx, MyProps { count, live, name }| {
     cx.render(rsx! {
         div {
-            h1 { "Hello, {cx.name}"}
-            h3 {"Are we alive? {cx.live}"}
-            p {"Count is {cx.count}"}
+            h1 { "Hello, {name}"}
+            h3 {"Are we alive? {live}"}
+            p {"Count is {count}"}
             { cx.children() }
         }
     })

+ 1 - 1
examples/reference/statemanagement.rs

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

+ 8 - 3
examples/reference/suspense.rs

@@ -14,13 +14,18 @@ struct DogApi {
 }
 const ENDPOINT: &str = "https://dog.ceo/api/breeds/image/random";
 
-pub static Example: FC<()> = |cx| {
+pub static Example: FC<()> = |cx, props| {
     let doggo = use_suspense(
         cx,
         || surf::get(ENDPOINT).recv_json::<DogApi>(),
         |cx, res| match res {
-            Ok(res) => rsx!(in cx, img { src: "{res.message}" }),
-            Err(_) => rsx!(in cx, div { "No doggos for you :(" }),
+            Ok(res) => rsx!(
+                cx,
+                img {
+                    src: "{res.message}"
+                }
+            ),
+            Err(_) => rsx!(cx, div { "No doggos for you :(" }),
         },
     );
 

+ 1 - 1
examples/reference/task.rs

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

+ 1 - 1
examples/reference/testing.rs

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

+ 2 - 2
examples/reference/tostring.rs

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

+ 7 - 6
examples/rsx_usage.rs

@@ -49,7 +49,7 @@ const NONE_ELEMENT: Option<()> = None;
 use baller::Baller;
 use dioxus::prelude::*;
 
-pub static Example: FC<()> = |cx| {
+pub static Example: FC<()> = |cx, props| {
     let formatting = "formatting!";
     let formatting_tuple = ("a", "b");
     let lazy_fmt = format_args!("lazily formatted text");
@@ -106,7 +106,7 @@ pub static Example: FC<()> = |cx| {
             // To fix this, call "render" method or use the "in" syntax to produce VNodes.
             // There's nothing we can do about it, sorry :/ (unless you want *really* unhygenic macros)
             {match true {
-                true => rsx!(in cx, h1 {"Top text"}),
+                true => rsx!(cx, h1 {"Top text"}),
                 false => cx.render(rsx!( h1 {"Bottom text"}))
             }}
 
@@ -117,9 +117,9 @@ pub static Example: FC<()> = |cx| {
 
             // True conditions need to be rendered (same reasons as matching)
             {if true {
-                rsx!(in cx, h1 {"Top text"})
+                rsx!(cx, h1 {"Top text"})
             } else {
-                rsx!(in cx, h1 {"Bottom text"})
+                rsx!(cx, h1 {"Bottom text"})
             }}
 
             // returning "None" is a bit noisy... but rare in practice
@@ -180,10 +180,11 @@ pub static Example: FC<()> = |cx| {
 
 mod baller {
     use super::*;
+    #[derive(PartialEq, Props)]
     pub struct BallerProps {}
 
     /// This component totally balls
-    pub fn Baller(cx: Context<()>) -> DomTree {
+    pub fn Baller<'a>(cx: Context<'a>, props: &BallerProps) -> DomTree<'a> {
         todo!()
     }
 }
@@ -194,7 +195,7 @@ pub struct TallerProps {
 }
 
 /// This component is taller than most :)
-pub fn Taller(cx: Context<TallerProps>) -> DomTree {
+pub fn Taller<'a>(cx: Context<'a>, props: &'a TallerProps) -> DomTree<'a> {
     let b = true;
     todo!()
 }

+ 7 - 7
examples/showcase.rs

@@ -11,12 +11,12 @@ fn main() {}
 use dioxus::prelude::*;
 use std::rc::Rc;
 
-static App: FC<()> = |cx| {
+static App: FC<()> = |cx, props| {
     let (selection, set_selection) = use_state(cx, || None as Option<usize>).classic();
 
     let body = match selection {
-        Some(id) => rsx!(in cx, ReferenceItem { selected: *id }),
-        None => rsx!(in cx, div { "Select an concept to explore" }),
+        Some(id) => rsx!(cx, ReferenceItem { selected: *id }),
+        None => rsx!(cx, div { "Select an concept to explore" }),
     };
 
     cx.render(rsx! {
@@ -33,7 +33,7 @@ struct ScrollSelectorProps<'a> {
     onselect: &'a dyn Fn(Option<usize>),
 }
 
-fn ScrollSelector<'a>(cx: Context<'a, ScrollSelectorProps>) -> DomTree<'a> {
+fn ScrollSelector<'a>(cx: Context<'a>, props: &'a ScrollSelectorProps) -> DomTree<'a> {
     let selection_list = (&REFERENCES).iter().enumerate().map(|(id, _)| {
         rsx! {
             li {
@@ -47,7 +47,7 @@ fn ScrollSelector<'a>(cx: Context<'a, ScrollSelectorProps>) -> DomTree<'a> {
             ul {
                 {selection_list}
                 button {
-                    onclick: move |_| (cx.onselect)(Some(10))
+                    onclick: move |_| (props.onselect)(Some(10))
                 }
             }
         }
@@ -59,8 +59,8 @@ struct ReferenceItemProps {
     selected: usize,
 }
 
-static ReferenceItem: FC<ReferenceItemProps> = |cx| {
-    let (caller, name, code) = REFERENCES[cx.selected];
+static ReferenceItem: FC<ReferenceItemProps> = |cx, props| {
+    let (caller, name, code) = REFERENCES[props.selected];
 
     // Create the component using the factory API directly
     let caller_node = LazyNodes::new(move |f| f.component(caller, (), None, &[]));

+ 0 - 112
examples/slideshow.rs

@@ -1,112 +0,0 @@
-//! Example: Webview Renderer
-//! -------------------------
-//!
-//! This example shows how to use the dioxus_desktop crate to build a basic desktop application.
-//!
-//! Under the hood, the dioxus_desktop crate bridges a native Dioxus VirtualDom with a custom prebuit application running
-//! in the webview runtime. Custom handlers are provided for the webview instance to consume patches and emit user events
-//! into the native VDom instance.
-//!
-//! Currently, NodeRefs won't work properly, but all other event functionality will.
-
-use dioxus::prelude::*;
-
-fn main() {
-    dioxus::desktop::launch(App, |c| c);
-}
-
-static App: FC<()> = |cx| {
-    let slides = use_state(cx, SlideController::new);
-
-    let slide = match slides.slide_id {
-        0 => cx.render(rsx!(Title {})),
-        1 => cx.render(rsx!(Slide1 {})),
-        2 => cx.render(rsx!(Slide2 {})),
-        3 => cx.render(rsx!(Slide3 {})),
-        _ => cx.render(rsx!(End {})),
-    };
-
-    cx.render(rsx! {
-        div {
-            style: {
-                background_color: "red"
-            }
-            div {
-                div { h1 {"my awesome slideshow"} }
-                div {
-                    button {"<-", onclick: move |_| slides.get_mut().go_forward()}
-                    h3 { "{slides.slide_id}" }
-                    button {"->" onclick: move |_| slides.get_mut().go_backward()}
-                 }
-            }
-            {slide}
-        }
-    })
-};
-
-#[derive(Clone)]
-struct SlideController {
-    slide_id: isize,
-}
-impl SlideController {
-    fn new() -> Self {
-        Self { slide_id: 0 }
-    }
-    fn can_go_forward(&self) -> bool {
-        false
-    }
-    fn can_go_backward(&self) -> bool {
-        true
-    }
-    fn go_forward(&mut self) {
-        if self.can_go_forward() {
-            self.slide_id += 1;
-        }
-    }
-    fn go_backward(&mut self) {
-        if self.can_go_backward() {
-            self.slide_id -= 1;
-        }
-    }
-}
-
-const Title: FC<()> = |cx| {
-    cx.render(rsx! {
-        div {
-            h1 { "Title" }
-            p {}
-        }
-    })
-};
-const Slide1: FC<()> = |cx| {
-    cx.render(rsx! {
-        div {
-            h1 { "Slide1" }
-            p {}
-        }
-    })
-};
-const Slide2: FC<()> = |cx| {
-    cx.render(rsx! {
-        div {
-            h1 { "Slide2" }
-            p {}
-        }
-    })
-};
-const Slide3: FC<()> = |cx| {
-    cx.render(rsx! {
-        div {
-            h1 { "Slide3" }
-            p {}
-        }
-    })
-};
-const End: FC<()> = |cx| {
-    cx.render(rsx! {
-        div {
-            h1 { "End" }
-            p {}
-        }
-    })
-};

+ 2 - 2
examples/ssr.rs

@@ -9,7 +9,7 @@ fn main() {
     println!("{}", ssr::render_vdom(&vdom, |c| c));
 }
 
-static App: FC<()> = |cx| {
+static App: FC<()> = |cx, props| {
     cx.render(rsx!(
         div {
             h1 { "Title" }
@@ -21,6 +21,6 @@ static App: FC<()> = |cx| {
 struct MyProps<'a> {
     text: &'a str,
 }
-fn App2<'a>(cx: Context<'a, MyProps>) -> DomTree<'a> {
+fn App2<'a>(cx: Context<'a>, props: &'a MyProps) -> DomTree<'a> {
     None
 }

+ 6 - 6
examples/tailwind.rs

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

+ 0 - 67
examples/testbed.rs

@@ -1,67 +0,0 @@
-use std::cell::Cell;
-
-use dioxus::prelude::*;
-use dioxus_core::{
-    nodes::{VElement, VText},
-    ElementId,
-};
-
-fn main() {
-    env_logger::init();
-    dioxus::desktop::launch(Example, |c| c);
-}
-
-const STYLE: &str = r#"
-body {background-color: powderblue;}
-h1   {color: blue;}
-p    {color: red;}
-"#;
-
-const Example: FC<()> = |cx| {
-    cx.render(rsx! {
-        Fragment {
-            Fragment {
-                Fragment {
-                    "h1"
-                    div {
-
-                    }
-                }
-                "h2"
-            }
-            "h3"
-        }
-        "h4"
-        div { "h5" }
-        button { }
-        Child {}
-    })
-};
-
-const Child: FC<()> = |cx| {
-    cx.render(rsx!(
-        h1 {"1" }
-        h1 {"2" }
-        h1 {"3" }
-        h1 {"4" }
-    ))
-};
-
-// this is a bad case that hurts our subtree memoization :(
-const AbTest: FC<()> = |cx| {
-    if 1 == 2 {
-        cx.render(rsx!(
-            h1 {"1"}
-            h1 {"2"}
-            h1 {"3"}
-            h1 {"4"}
-        ))
-    } else {
-        cx.render(rsx!(
-            h1 {"1"}
-            h1 {"2"}
-            h2 {"basd"}
-            h1 {"4"}
-        ))
-    }
-};

+ 43 - 46
examples/todomvc.rs

@@ -22,7 +22,7 @@ pub struct TodoItem {
 }
 
 const STYLE: &str = include_str!("./_examples/todomvc/style.css");
-const App: FC<()> = |cx| {
+const App: FC<()> = |cx, props| {
     let draft = use_state(cx, || "".to_string());
     let todos = use_state(cx, || HashMap::<u32, Rc<TodoItem>>::new());
     let filter = use_state(cx, || FilterState::All);
@@ -48,63 +48,60 @@ const App: FC<()> = |cx| {
         _ => "items",
     };
 
-    cx.render(rsx! {
-        div { id: "app"
-            style {"{STYLE}"}
-            div {
-                header { class: "header"
-                    h1 {"todos"}
-                    input {
-                        class: "new-todo"
-                        placeholder: "What needs to be done?"
-                        value: "{draft}"
-                        oninput: move |evt| draft.set(evt.value())
-                    }
+    rsx!(cx, div { id: "app"
+        style {"{STYLE}"}
+        div {
+            header { class: "header"
+                h1 {"todos"}
+                input {
+                    class: "new-todo"
+                    placeholder: "What needs to be done?"
+                    value: "{draft}"
+                    oninput: move |evt| draft.set(evt.value())
                 }
-                {todolist}
-                {(!todos.is_empty()).then(|| rsx!(
-                    footer {
-                        span { strong {"{items_left}"} span {"{item_text} left"} }
-                        ul { class: "filters"
-                            li { class: "All", a { href: "", onclick: move |_| filter.set(FilterState::All), "All" }}
-                            li { class: "Active", a { href: "active", onclick: move |_| filter.set(FilterState::Active), "Active" }}
-                            li { class: "Completed", a { href: "completed", onclick: move |_| filter.set(FilterState::Completed), "Completed" }}
-                        }
-                    }
-                ))}
-            }
-            footer { class: "info"
-                p {"Double-click to edit a todo"}
-                p { "Created by ", a { "jkelleyrtp", href: "http://github.com/jkelleyrtp/" }}
-                p { "Part of ", a { "TodoMVC", href: "http://todomvc.com" }}
             }
+            {todolist}
+            {(!todos.is_empty()).then(|| rsx!(
+                footer {
+                    span { strong {"{items_left}"} span {"{item_text} left"} }
+                    ul { class: "filters"
+                        li { class: "All", a { href: "", onclick: move |_| filter.set(FilterState::All), "All" }}
+                        li { class: "Active", a { href: "active", onclick: move |_| filter.set(FilterState::Active), "Active" }}
+                        li { class: "Completed", a { href: "completed", onclick: move |_| filter.set(FilterState::Completed), "Completed" }}
+                    }
+                }
+            ))}
+        }
+        footer { class: "info"
+            p {"Double-click to edit a todo"}
+            p { "Created by ", a { "jkelleyrtp", href: "http://github.com/jkelleyrtp/" }}
+            p { "Part of ", a { "TodoMVC", href: "http://todomvc.com" }}
         }
     })
 };
 
 #[derive(PartialEq, Props)]
 pub struct TodoEntryProps {
-    todo: std::rc::Rc<TodoItem>,
+    todo: Rc<TodoItem>,
 }
 
-pub fn TodoEntry(cx: Context<TodoEntryProps>) -> DomTree {
-    let TodoEntryProps { todo } = *cx;
+pub fn TodoEntry<'a>(cx: Context<'a>, props: &TodoEntryProps) -> DomTree<'a> {
     let is_editing = use_state(cx, || false);
-    let contents = "";
+    let contents = use_state(cx, || String::from(""));
+    let todo = &props.todo;
 
-    cx.render(rsx! (
-        li {
-            "{todo.id}"
+    rsx!(cx, li {
+        "{todo.id}"
+        input {
+            class: "toggle"
+            r#type: "checkbox"
+            "{todo.checked}"
+        }
+       {is_editing.then(|| rsx!{
             input {
-                class: "toggle"
-                r#type: "checkbox"
-                "{todo.checked}"
+                value: "{contents}"
+                oninput: move |evt| contents.set(evt.value())
             }
-           {is_editing.then(|| rsx!{
-                input {
-                    value: "{contents}"
-                }
-            })}
-        }
-    ))
+        })}
+    })
 }

+ 4 - 4
examples/web_tick.rs

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

+ 0 - 48
examples/webview.rs

@@ -1,48 +0,0 @@
-//! Example: Webview Renderer
-//! -------------------------
-//!
-//! This example shows how to use the dioxus_desktop crate to build a basic desktop application.
-//!
-//! Under the hood, the dioxus_desktop crate bridges a native Dioxus VirtualDom with a custom prebuit application running
-//! in the webview runtime. Custom handlers are provided for the webview instance to consume patches and emit user events
-//! into the native VDom instance.
-//!
-//! Currently, NodeRefs won't work properly, but all other event functionality will.
-#![allow(non_upper_case_globals, non_snake_case)]
-
-use dioxus::{events::on::MouseEvent, prelude::*};
-
-fn main() -> anyhow::Result<()> {
-    env_logger::init();
-    dioxus::desktop::launch(App, |c| c)
-}
-
-static App: FC<()> = |cx| {
-    let state = use_state(cx, || String::from("hello"));
-    let clear_text = state == "hello";
-
-    dbg!("rednering parent");
-    cx.render(rsx! {
-        div {
-            h1 {"{state}"}
-            CalculatorKey { name: "key-clear", onclick: move |_| state.get_mut().push_str("hello"), "{clear_text}" }
-            CalculatorKey { name: "key-sign", onclick: move |_| { state.get_mut().pop(); }, "±"}
-        }
-    })
-};
-
-#[derive(Props)]
-struct CalculatorKeyProps<'a> {
-    name: &'static str,
-    onclick: &'a dyn Fn(MouseEvent),
-}
-
-fn CalculatorKey<'a, 'r>(cx: Context<'a, CalculatorKeyProps<'r>>) -> DomTree<'a> {
-    cx.render(rsx! {
-        button {
-            class: "calculator-key {cx.name}"
-            onclick: {cx.onclick}
-            {cx.children()}
-        }
-    })
-}

+ 1 - 1
examples/webview_web.rs

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

+ 1 - 1
notes/Parity.md

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

+ 5 - 5
notes/SOLVEDPROBLEMS.md

@@ -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:
 
 ```rust
-pub static Example: FC<()> = |cx| {
+pub static Example: FC<()> = |cx, props|{
     html! { <div> "blah" </div> }
 };
 
 // expands to...
 
-pub static Example: FC<()> = |cx| {
+pub static Example: FC<()> = |cx, props|{
     // This function converts a Fn(allocator) -> DomTree closure to a VNode struct that will later be evaluated.
     html_macro_to_vnodetree(move |allocator| {
         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:
 
 ```rust
-static APP: FC<()> = |cx| {
+static APP: FC<()> = |cx, props|{
     let title = use_context(Title);
     cx.render(html!{
         <div>
@@ -334,7 +334,7 @@ static APP: FC<()> = |cx| {
         </div>
     })
 };
-static HEAVY_LIST: FC<()> = |cx| {
+static HEAVY_LIST: FC<()> = |cx, props|{
     cx.render({
         {0.100.map(i => <BigElement >)}
     })
@@ -378,7 +378,7 @@ struct Props {
 
 }
 
-static Component: FC<Props> = |cx| {
+static Component: FC<Props> = |cx, props|{
 
 }
 ```

+ 0 - 1
packages/core-macro/examples/fc.rs

@@ -1 +0,0 @@
-fn main() {}

+ 1 - 1
packages/core-macro/examples/prop_test.rs

@@ -20,5 +20,5 @@ struct SomeProps {
 /// This implementation does not require a "PartialEq" because it does not memoize
 #[derive(dioxus_core_macro::Props)]
 struct SomePropsTwo<'a> {
-    a: &'a str,
+    _a: &'a str,
 }

+ 0 - 125
packages/core-macro/examples/rsxt.rs

@@ -1,125 +0,0 @@
-pub mod dioxus {
-    pub mod builder {
-        pub struct Builder;
-
-        struct AttrVal;
-
-        impl Into<AttrVal> for &'static str {
-            fn into(self) -> AttrVal {
-                todo!()
-            }
-        }
-
-        impl Into<AttrVal> for String {
-            fn into(self) -> AttrVal {
-                todo!()
-            }
-        }
-        // impl<T> From<T> for AttrVal {
-        //     fn from(_: T) -> Self {
-        //         todo!()
-        //     }
-        // }
-
-        impl Builder {
-            // fn attr<T>(mut self, key: &str, value: impl Into<AttrVal>) -> Self {
-            pub fn attr<T>(self, _key: &str, _value: T) -> Self {
-                Self
-            }
-
-            pub fn on<T>(self, _key: &str, _value: T) -> Self {
-                Self
-            }
-
-            pub fn finish(self) {
-                // Self
-            }
-        }
-
-        pub struct Bump;
-        pub fn div(_bump: &Bump) -> Builder {
-            todo!()
-        }
-        pub fn h1(_bump: &Bump) -> Builder {
-            todo!()
-        }
-        pub fn h2(_bump: &Bump) -> Builder {
-            todo!()
-        }
-    }
-}
-
-pub fn main() {
-    // render(rsx! {
-    //     div { // we can actually support just a list of nodes too
-    //         h1 {"Hello Dioxus"}
-    //         p {"This is a beautful app you're building"}
-    //         section {
-    //             "custom section to the rescue",
-    //             class: "abc123"
-    //         }
-    //         span {
-    //             class: "abc123"
-    //             "Try backwards too."
-    //             "Anything goes!"
-    //             "As long as it's within the rules"
-    //             {0..10.map(|f| rsx!{
-    //                 div {
-    //                     h3 {"totally okay to drop in iterators and expressions"}
-    //                     p {"however, debug information is lost"}
-    //                 }
-    //             })}
-    //         }
-    //         span {
-    //             "Feel free"
-    //             class: "abc123"
-    //             "To mix to your heart's content"
-    //         }
-    //         span { class: "some-very-long-and-tedious-class-name-is-now-separated"
-    //             "Very ergonomic"
-    //         }
-    //         span { "Innovative design 🛠"
-    //             class: "some-very-long-and-tedious-class-name-is-now-separated"
-    //         }
-    //     }
-    // });
-
-    let _g = String::from("asd");
-
-    // let lazy = rsx! {
-    //     div {
-    //         a: "asd",
-    //         a: "asd",
-    //         a: "asd",
-    //         a: "asd",
-    //         a: "asd",
-    //         // a: {rsx!{ h1 {"hello world"} }}, // include
-    //         a: {&g},
-    //         b: {1 + 2},
-    //         onclick: {move |e: ()| {
-    //             println!("hello world!")
-    //         }},
-    //         div {
-    //             a: "asd"
-    //             div {
-    //                 div {
-    //                     div {
-
-    //                     }
-    //                 }
-    //             }
-    //         }
-    //         h1 {
-
-    //         }
-    //         h2 {
-    //             "child"
-    //         }
-    //         "Childnode"
-    //     }
-    // };
-
-    // render(lazy);
-}
-
-fn render(_f: impl Fn(&dioxus::builder::Bump)) {}

+ 2 - 2
packages/core-macro/src/ifmt.rs

@@ -237,8 +237,8 @@ where
                 // # Safety
                 //
                 //   - This is the canonical example of using `ManuallyDrop`.
-                let value = ManuallyDrop::into_inner(ptr::read(&mut self.0));
-                let drop = ManuallyDrop::into_inner(ptr::read(&mut self.1));
+                let value = ManuallyDrop::into_inner(ptr::read(&self.0));
+                let drop = ManuallyDrop::into_inner(ptr::read(&self.1));
                 drop(value);
             }
         }

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

@@ -30,7 +30,7 @@ pub fn derive_typed_builder(input: proc_macro::TokenStream) -> proc_macro::Token
 ///
 /// ## Complete Reference Guide:
 /// ```
-/// const Example: FC<()> = |cx| {
+/// const Example: FC<()> = |cx, props|{
 ///     let formatting = "formatting!";
 ///     let formatting_tuple = ("a", "b");
 ///     let lazy_fmt = format_args!("lazily formatted text");
@@ -87,7 +87,7 @@ pub fn derive_typed_builder(input: proc_macro::TokenStream) -> proc_macro::Token
 ///             // To fix this, call "render" method or use the "in" syntax to produce VNodes.
 ///             // There's nothing we can do about it, sorry :/ (unless you want *really* unhygenic macros)
 ///             {match true {
-///                 true => rsx!(in cx, h1 {"Top text"}),
+///                 true => rsx!(cx, h1 {"Top text"}),
 ///                 false => cx.render(rsx!( h1 {"Bottom text"}))
 ///             }}
 ///
@@ -98,9 +98,9 @@ pub fn derive_typed_builder(input: proc_macro::TokenStream) -> proc_macro::Token
 ///
 ///             // True conditions need to be rendered (same reasons as matching)
 ///             {if true {
-///                 rsx!(in cx, h1 {"Top text"})
+///                 rsx!(cx, h1 {"Top text"})
 ///             } else {
-///                 rsx!(in cx, h1 {"Bottom text"})
+///                 rsx!(cx, h1 {"Bottom text"})
 ///             }}
 ///
 ///             // returning "None" is a bit noisy... but rare in practice

+ 2 - 2
packages/core-macro/src/rsx/ambiguous.rs

@@ -86,11 +86,11 @@ impl Parse for AmbiguousElement<AS_HTML> {
             if first_char.is_ascii_uppercase() {
                 input
                     .parse::<Component<AS_HTML>>()
-                    .map(|c| AmbiguousElement::Component(c))
+                    .map(AmbiguousElement::Component)
             } else {
                 input
                     .parse::<Element<AS_HTML>>()
-                    .map(|c| AmbiguousElement::Element(c))
+                    .map(AmbiguousElement::Element)
             }
         } else {
             Err(Error::new(input.span(), "Not a valid Html tag"))

+ 1 - 2
packages/core-macro/src/rsx/body.rs

@@ -39,8 +39,7 @@ impl Parse for RsxBody<AS_HTML> {
 }
 
 fn try_parse_custom_context(input: ParseStream) -> Result<Option<Ident>> {
-    let res = if input.peek(Token![in]) && input.peek2(Ident) && input.peek3(Token![,]) {
-        let _ = input.parse::<Token![in]>()?;
+    let res = if input.peek(Ident) && input.peek2(Token![,]) {
         let name = input.parse::<Ident>()?;
         input.parse::<Token![,]>()?;
         Some(name)

+ 1 - 1
packages/core-macro/src/rsx/element.rs

@@ -270,7 +270,7 @@ fn parse_rsx_element_field(
             name,
             value: ty,
             namespace: None,
-            element_name: element_name.clone(),
+            element_name,
         });
         return Ok(());
     }

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

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

+ 1 - 1
packages/core/.vscode/settings.json

@@ -1,3 +1,3 @@
 {
-  "rust-analyzer.inlayHints.enable": false
+  "rust-analyzer.inlayHints.enable": true
 }

+ 2 - 2
packages/core/README.md

@@ -15,7 +15,7 @@ Dioxus-core builds off the many frameworks that came before it. Notably, Dioxus
 - Preact: approach for normalization and ref
 - Yew: passion and inspiration ❤️
 
-Dioxus-core leverages some really cool techniques and hits a very high level of parity with mature frameworks. Some unique features include:
+Dioxus-core leverages some really cool techniques and hits a very high level of parity with mature frameworks. However, Dioxus also brings some new unique features:
 
 - managed lifetimes for borrowed data
 - suspended nodes (task/fiber endpoints) for asynchronous vnodes
@@ -24,7 +24,7 @@ Dioxus-core leverages some really cool techniques and hits a very high level of
 - slab allocator for scopes
 - mirrored-slab approach for remote vdoms
 
-There's certainly more to the story, but these optimizations make Dioxus memory use and allocation count extremely minimal. For an average application, it is likely that zero allocations will need to be performed once the app has been mounted. Only when new components are added to the dom will allocations occur - and only en mass. The space of old VNodes is dynamically recycled as new nodes are added. Additionally, Dioxus tracks the average memory footprint of previous components to estimate how much memory allocate for future components.
+There's certainly more to the story, but these optimizations make Dioxus memory use and allocation count extremely minimal. For an average application, it is possible that zero allocations will need to be performed once the app has been mounted. Only when new components are added to the dom will allocations occur - and only en mass. The space of old VNodes is dynamically recycled as new nodes are added. Additionally, Dioxus tracks the average memory footprint of previous components to estimate how much memory allocate for future components.
 
 All in all, Dioxus treats memory as an incredibly valuable resource. Combined with the memory-efficient footprint of WASM compilation, Dioxus apps can scale to thousands of components and still stay snappy and respect your RAM usage.
 

+ 4 - 4
packages/core/benches/jsframework.rs

@@ -22,7 +22,7 @@ criterion_group!(mbenches, create_rows);
 criterion_main!(mbenches);
 
 fn create_rows(c: &mut Criterion) {
-    static App: FC<()> = |cx| {
+    static App: FC<()> = |cx, _| {
         let mut rng = SmallRng::from_entropy();
         let rows = (0..10_000).map(|f| {
             let label = Label::new(&mut rng);
@@ -56,11 +56,11 @@ struct RowProps {
     row_id: usize,
     label: Label,
 }
-fn Row<'a>(cx: Context<'a, RowProps>) -> DomTree {
-    let [adj, col, noun] = cx.label.0;
+fn Row<'a>(cx: Context<'a>, props: &RowProps) -> DomTree<'a> {
+    let [adj, col, noun] = props.label.0;
     cx.render(rsx! {
         tr {
-            td { class:"col-md-1", "{cx.row_id}" }
+            td { class:"col-md-1", "{props.row_id}" }
             td { class:"col-md-1", onclick: move |_| { /* run onselect */ }
                 a { class: "lbl", "{adj}" "{col}" "{noun}" }
             }

+ 6 - 2
packages/core/examples/alternative.rs

@@ -1,8 +1,12 @@
 use dioxus_core::prelude::*;
 
-fn main() {}
+fn main() {
+    let mut dom = VirtualDom::new(EXAMPLE);
+    dom.rebuild();
+    println!("{}", dom);
+}
 
-pub static Example: FC<()> = |cx| {
+pub static EXAMPLE: FC<()> = |cx, _| {
     let list = (0..10).map(|_f| LazyNodes::new(move |_f| todo!()));
 
     cx.render(LazyNodes::new(move |cx| {

+ 8 - 32
packages/core/examples/async.rs

@@ -1,39 +1,15 @@
 use dioxus_core::prelude::*;
 
-fn main() {}
-
-const App: FC<()> = |cx| {
-    // create a new future
-    let _fut = cx.use_hook(
-        |_| {
-            //
-            async { loop {} }
-            // Box::pin(async { loop {} }) as Pin<Box<dyn Future<Output = ()>>>
-        },
-        |f| f,
-        |_| {},
-    );
-    // let g = unsafe { Pin::new_unchecked(fut) };
-
-    // cx.submit_task(fut);
-
-    todo!()
-};
-
-const Task: FC<()> = |cx| {
-    let (_task, _res) = use_task(cx, || async { true });
-    // task.pause();
-    // task.restart();
-    // task.stop();
-    // task.drop();
+fn main() {
+    let mut dom = VirtualDom::new(App);
+    dom.rebuild();
+}
 
-    //
+const App: FC<()> = |cx, props| {
+    let id = cx.scope_id();
+    cx.submit_task(Box::pin(async move { id }));
 
-    let _s = use_task(cx, || async { "hello world".to_string() });
+    let (handle, contents) = use_task(cx, || async { "hello world".to_string() });
 
     todo!()
 };
-
-fn use_mut<P, T>(_cx: Context<P>, _f: impl FnOnce() -> T) -> &mut T {
-    todo!()
-}

+ 2 - 2
packages/core/examples/borrowed.rs

@@ -20,7 +20,7 @@ struct ListItem {
     age: u32,
 }
 
-fn app(cx: Context<AppProps>) -> DomTree {
+fn app<'a>(cx: Context<'a>, props: &AppProps) -> DomTree<'a> {
     // let (val, set_val) = use_state_classic(cx, || 0);
 
     cx.render(LazyNodes::new(move |_nodecx| {
@@ -56,7 +56,7 @@ struct ChildProps {
     item_handler: Rc<dyn Fn(i32)>,
 }
 
-fn ChildItem<'a>(cx: Context<'a, ChildProps>) -> DomTree {
+fn ChildItem<'a>(cx: Context<'a>, props: &'a ChildProps) -> DomTree<'a> {
     cx.render(LazyNodes::new(move |__cx| todo!()))
 }
 

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

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

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

@@ -2,7 +2,7 @@ use dioxus_core::prelude::*;
 
 fn main() {}
 
-fn app(cx: Context<()>) -> DomTree {
+fn app<'a>(cx: Context<'a>, props: &()) -> DomTree<'a> {
     let vak = use_suspense(
         cx,
         || async {},

+ 4 - 4
packages/core/examples/jsframework.rs

@@ -10,7 +10,7 @@ fn main() {
     assert!(g.edits.len() > 1);
 }
 
-static App: FC<()> = |cx| {
+static App: FC<()> = |cx, props| {
     let mut rng = SmallRng::from_entropy();
     let rows = (0..10_000).map(|f| {
         let label = Label::new(&mut rng);
@@ -35,12 +35,12 @@ struct RowProps {
     row_id: usize,
     label: Label,
 }
-fn Row<'a>(cx: Context<'a, RowProps>) -> DomTree {
+fn Row<'a>(cx: Context<'a>, props: &'a RowProps) -> DomTree<'a> {
     cx.render(rsx! {
         tr {
-            td { class:"col-md-1", "{cx.row_id}" }
+            td { class:"col-md-1", "{props.row_id}" }
             td { class:"col-md-1", onclick: move |_| { /* run onselect */ }
-                a { class: "lbl", "{cx.label}" }
+                a { class: "lbl", "{props.label}" }
             }
             td { class: "col-md-1"
                 a { class: "remove", onclick: move |_| {/* remove */}

+ 3 - 2
packages/core/examples/vdom_usage.rs

@@ -4,12 +4,13 @@ use dioxus_core::prelude::*;
 
 #[async_std::main]
 async fn main() {
-    static App: FC<()> = |cx| 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);
 
     dom.rebuild();
 
     let deadline = async_std::task::sleep(Duration::from_millis(50));
-    let _fut = dom.run_with_deadline(deadline);
+
+    // let _fut = dom.run_with_deadline(|| deadline.);
 }

+ 5 - 0
packages/core/src/bumpframe.rs

@@ -14,6 +14,7 @@ pub(crate) struct BumpFrame {
     pub bump: Bump,
     pub(crate) head_node: VNode<'static>,
 
+    #[cfg(test)]
     // used internally for debugging
     _name: &'static str,
 }
@@ -23,11 +24,15 @@ impl ActiveFrame {
         let frame_a = BumpFrame {
             bump: Bump::new(),
             head_node: NodeFactory::unstable_place_holder(),
+
+            #[cfg(test)]
             _name: "wip",
         };
         let frame_b = BumpFrame {
             bump: Bump::new(),
             head_node: NodeFactory::unstable_place_holder(),
+
+            #[cfg(test)]
             _name: "fin",
         };
         Self {

+ 1 - 2
packages/core/src/childiter.rs

@@ -39,7 +39,7 @@ impl<'a> Iterator for RealChildIterator<'a> {
                         // We've recursed INTO an element/text
                         // We need to recurse *out* of it and move forward to the next
                         should_pop = true;
-                        returned_node = Some(&*node);
+                        returned_node = Some(node);
                     }
 
                     // If we get a fragment we push the next child
@@ -64,7 +64,6 @@ impl<'a> Iterator for RealChildIterator<'a> {
                             .scopes
                             .get_scope(sc.associated_scope.get().unwrap())
                             .unwrap();
-                        // let scope = self.scopes.get(sc.ass_scope.get().unwrap()).unwrap();
 
                         // Simply swap the current node on the stack with the root of the component
                         *node = scope.frames.fin_head();

Some files were not shown because too many files changed in this diff