Merge pull request #28 from DioxusLabs/alex/reference-review

Various typos/grammar/rewording
This commit is contained in:
Jonathan Kelley 2021-10-27 14:14:39 -04:00 committed by GitHub
commit dc6575ad86
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
50 changed files with 168 additions and 168 deletions

View file

@ -161,11 +161,11 @@ Dioxus is heavily inspired by React, but we want your transition to feel like an
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. 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.
### Isn't the overhead for interacting with the DOM from WASM too much? ### 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. 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.
### Aren't WASM binaries too huge to deploy in production? ### 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. 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. For reference, Dioxus `hello-world` clocks in at around 70kb gzip or 60kb brotli, and Dioxus supports SSR.
@ -176,7 +176,7 @@ There are plenty Rust Elm-like frameworks in the world - we were not interested
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. 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? ### 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. 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? ### 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 - Yew and Seed use an Elm-like pattern and don't support SSR or any alternate rendering platforms
@ -193,7 +193,7 @@ In the future, we are interested in using Webrenderer to provide a fully native
You shouldn't use Dioxus if: You shouldn't use Dioxus if:
- You don't like the React Hooks approach to frontend - You don't like the React Hooks approach to frontend
- You need a no-std renderer - You need a no-std renderer
- You want to support browsers where WASM or asm.js are not supported. - You want to support browsers where Wasm or asm.js are not supported.
## License ## License

View file

@ -24,7 +24,7 @@ The Dioxus API and patterns closely resemble React - if this guide is lacking in
### Web Support ### Web Support
--- ---
The Web is the most-supported target platform for Dioxus. To run on the Web, your app must be compiled to WebAssembly and depend on the `dioxus` crate with the `web` feature enabled. Because of the WASM limitation, not every crate will work with your web-apps, so you'll need to make sure that your crates work without native system calls (timers, IO, etc). The Web is the most-supported target platform for Dioxus. To run on the Web, your app must be compiled to WebAssembly and depend on the `dioxus` crate with the `web` feature enabled. Because of the Wasm limitation, not every crate will work with your web-apps, so you'll need to make sure that your crates work without native system calls (timers, IO, etc).
Because the web is a fairly mature platform, we expect there to be very little API churn for web-based features. Because the web is a fairly mature platform, we expect there to be very little API churn for web-based features.
@ -88,7 +88,7 @@ Examples:
### LiveView Support ### LiveView Support
--- ---
The internal architecture of Dioxus was designed from day one to support the `LiveView` use-case, where a web server hosts a running app for each connected user. As of today, there is no out-of-the-box LiveView support - you'll need to wire this up yourself. While not currently fully implemented, the expectation is that LiveView apps can be a hybrid between WASM and server-rendered where only portions of a page are "live" and the rest of the page is either server-rendered, statically generated, or handled by the host SPA. The internal architecture of Dioxus was designed from day one to support the `LiveView` use-case, where a web server hosts a running app for each connected user. As of today, there is no out-of-the-box LiveView support - you'll need to wire this up yourself. While not currently fully implemented, the expectation is that LiveView apps can be a hybrid between Wasm and server-rendered where only portions of a page are "live" and the rest of the page is either server-rendered, statically generated, or handled by the host SPA.

View file

@ -228,7 +228,7 @@ For example, the `div` element is (approximately!) defined as such:
```rust ```rust
struct div; struct div;
impl div { impl div {
/// Some glorious documentaiton about the class proeprty. /// Some glorious documentation about the class property.
#[inline] #[inline]
fn class<'a>(&self, cx: NodeFactory<'a>, val: Arguments) -> Attribute<'a> { fn class<'a>(&self, cx: NodeFactory<'a>, val: Arguments) -> Attribute<'a> {
cx.attr("class", val, None, false) cx.attr("class", val, None, false)

View file

@ -1,12 +1,12 @@
# Dioxus Liveview # Dioxus Liveview
Liveview is a configuration where a server and a client work together to render a Dioxus app. Liveview monomorphizes a web application, eliminating the need for frontend-specific APIs. Liveview is a configuration where a server and a client work together to render a Dioxus app. Liveview monomorphizes a web application, eliminating the need for frontend-specific APIs.
This is a developer-friendly alternative to the JAM-stack (Javascript + API + Markdown), combining the WASM-compatibility and async performance of Rust. This is a developer-friendly alternative to the JAM-stack (Javascript + API + Markdown), combining the Wasm-compatibility and async performance of Rust.
## Why liveview? ## Why liveview?
### No APIs necessary! ### No APIs necessary!
Because Liveview combines the server and the client, you'll find dedicated APIs unnecessary. You'll still want to implement a datafetching service for Live-apps, but this can be implemented as a crate and shared between apps. This approach was designed to let you model out your data requirements without needing to maintain a public versioned API. Because Liveview combines the server and the client, you'll find dedicated APIs unnecessary. You'll still want to implement a data-fetching service for Live-apps, but this can be implemented as a crate and shared between apps. This approach was designed to let you model out your data requirements without needing to maintain a public versioned API.
You can find more information to data modeling and fetching for LiveApps in the "Book of Dioxus Patterns". You can find more information to data modeling and fetching for LiveApps in the "Book of Dioxus Patterns".

View file

@ -6,7 +6,7 @@ Yew subscriptions are used to schedule update for components into the future. Th
fn Component(cx: Component<()>) -> DomTree { fn Component(cx: Component<()>) -> DomTree {
let update = cx.schedule(); let update = cx.schedule();
// Now, when the subscription is called, the component will be re-evaluted // Now, when the subscription is called, the component will be re-evaluated
update.consume(); update.consume();
} }
``` ```

View file

@ -56,7 +56,7 @@ async fn ExampleLoader(cx: Context<()>) -> Vnode {
match name { match name {
Ok(name) => rsx! { <div> "Hello {something}" </div> }, Ok(name) => rsx! { <div> "Hello {something}" </div> },
Err(e) => rsx! { <div> "An error occured :(" </div>} Err(e) => rsx! { <div> "An error occurred :(" </div>}
} }
} }
``` ```

View file

@ -53,4 +53,4 @@ fn test(cx: Context<()>) -> DomTree {
} }
``` ```
While the contents of the destructued bundle might change, not every child component will need to be re-rendered. While the contents of the destructured bundle might change, not every child component will need to be re-rendered.

View file

@ -49,7 +49,7 @@ To speed up the process of building our elements and text, Dioxus uses a special
- Bumpalo: [https://github.com/fitzgen/bumpalo](https://github.com/fitzgen/bumpalo) - Bumpalo: [https://github.com/fitzgen/bumpalo](https://github.com/fitzgen/bumpalo)
- Dodrio: [https://github.com/fitzgen/dodrio](https://github.com/fitzgen/dodrio) - Dodrio: [https://github.com/fitzgen/dodrio](https://github.com/fitzgen/dodrio)
In other frontend frameworks for Rust, nearly every string is allocated using the global allocator. This means that strings in Rust do not benefit from the immutable string interning optimizations that JavaScript engines employ. By using a smaller, faster, more limited allocator, we can increase framework performance, bypassing even the naive WasmBindgen benchmarks for very quick renders. In other frontend frameworks for Rust, nearly every string is allocated using the global allocator. This means that strings in Rust do not benefit from the immutable string interning optimizations that JavaScript engines employ. By using a smaller, faster, more limited allocator, we can increase framework performance, bypassing even the naive wasm-bindgen benchmarks for very quick renders.
It's important to note that VNodes are not `'static` - the VNode definition has a lifetime attached to it: It's important to note that VNodes are not `'static` - the VNode definition has a lifetime attached to it:

View file

@ -78,7 +78,7 @@ If you plan to develop extensions for the `Dioxus` ecosystem, please use the `di
Now, let's edit our `main.rs` file: Now, let's edit our `main.rs` file:
```rust ```rust
use diouxs::prelude::*; use dioxus::prelude::*;
fn main() { fn main() {
@ -97,7 +97,7 @@ Let's dissect our example a bit.
This bit of code imports everything from the the `prelude` module. This brings into scope the right traits, types, and macros needed for working with Dioxus. This bit of code imports everything from the the `prelude` module. This brings into scope the right traits, types, and macros needed for working with Dioxus.
```rust ```rust
use diouxs::prelude::*; use dioxus::prelude::*;
``` ```
This initialization code launches a Tokio runtime on a helper thread - where your code will run, and then the WebView on the main-thread. Due to platform requirements, the main thread is blocked by this call. This initialization code launches a Tokio runtime on a helper thread - where your code will run, and then the WebView on the main-thread. Due to platform requirements, the main thread is blocked by this call.

View file

@ -2,14 +2,14 @@
## Running Examples ## Running Examples
We use the dedicated `dioxus-cli` to build and test dioxus web-apps. This can run examples, tests, build web workers, launch development servers, bundle, and more. It's general purpose, but currently very tailored to Dioxus for liveview and bundling. If you've not used it before, `cargo install --path pacakages/dioxus-cli` will get it installed. This CLI tool should feel like using `cargo` but with 1st party support for assets, bundling, and other important dioxus-specific features. We use the dedicated `dioxus-cli` to build and test dioxus web-apps. This can run examples, tests, build web workers, launch development servers, bundle, and more. It's general purpose, but currently very tailored to Dioxus for liveview and bundling. If you've not used it before, `cargo install --path packages/dioxus-cli` will get it installed. This CLI tool should feel like using `cargo` but with 1st party support for assets, bundling, and other important dioxus-specific features.
Alternatively, `trunk` works but can't run examples. Alternatively, `trunk` works but can't run examples.
- tide_ssr: Handle an HTTP request and return an html body using the html! macro. `cargo run --example tide_ssr` - tide_ssr: Handle an HTTP request and return an html body using the html! macro. `cargo run --example tide_ssr`
- doc_generator: Use dioxus SSR to generate the website and docs. `cargo run --example doc_generator` - doc_generator: Use dioxus SSR to generate the website and docs. `cargo run --example doc_generator`
- fc_macro: Use the functional component macro to build terse components. `cargo run --example fc_macro` - fc_macro: Use the functional component macro to build terse components. `cargo run --example fc_macro`
- hello_web: Start a simple wasm app. Requires a web packer like dioxus-cli or trunk `cargo run --example hello` - hello_web: Start a simple Wasm app. Requires a web packer like dioxus-cli or trunk `cargo run --example hello`
- router: `cargo run --example router` - router: `cargo run --example router`
- tide_ssr: `cargo run --example tide_ssr` - tide_ssr: `cargo run --example tide_ssr`
- webview: Use liveview to bridge into a webview context for a simple desktop application. `cargo run --example webview` - webview: Use liveview to bridge into a webview context for a simple desktop application. `cargo run --example webview`

View file

@ -1,3 +1,3 @@
# The WASM Guide # The Wasm Guide
This guide will help you build your first app that leverages WASM in the browser to display the user interface. This guide will help you build your first app that leverages Wasm in the browser to display the user interface.

View file

@ -12,7 +12,7 @@ fn live_component(cx: &Context<()>) -> DomTree {
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
|| html! { <div> {"Loading data from server..."} </div> }, || html! { <div> {"Loading data from server..."} </div> },
// Renderered on the server // Rendered on the server
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
|| html! { <div> {"Server Data Loaded!"} </div> }, || html! { <div> {"Server Data Loaded!"} </div> },
) )

View file

@ -1,6 +1,6 @@
# Examples # Examples
Most of these examples are run through webview so you don't need the dioxus cli installed to preview the functionality. Most of these examples are run through webview so you don't need the Dioxus CLI installed to preview the functionality.
These examples are fully-fledged micro apps. They can be ran with the `cargo run --example XYZ` These examples are fully-fledged micro apps. They can be ran with the `cargo run --example XYZ`

View file

@ -15,10 +15,10 @@
//! For now, this example shows how to use coroutines used with use_state. //! For now, this example shows how to use coroutines used with use_state.
//! //!
//! //!
//! ## What is a Couroutine? //! ## What is a Coroutine?
//! //!
//! A coroutine is a function that can be paused and resumed. It can be paused internally through "await" or externally //! A coroutine is a function that can be paused and resumed. It can be paused internally through "await" or externally
//! using the `TaskHandle` API. Within a coroutine, you may execute asynchonous code, that modifies values captured when //! using the `TaskHandle` API. Within a coroutine, you may execute asynchronous code, that modifies values captured when
//! the coroutine was initiated. `use_state` always returns the same setter, so you don't need to worry about //! the coroutine was initiated. `use_state` always returns the same setter, so you don't need to worry about
fn main() { fn main() {

View file

@ -1,4 +1,4 @@
//! Example: realworld usage of hydration //! Example: real-world usage of hydration
//! ------------------------------------ //! ------------------------------------
//! //!
//! This example shows how to pre-render a page using dioxus SSR and then how to rehydrate it on the client side. //! This example shows how to pre-render a page using dioxus SSR and then how to rehydrate it on the client side.

View file

@ -1,7 +1,7 @@
//! Example: Reducer Pattern //! Example: Reducer Pattern
//! ----------------- //! -----------------
//! //!
//! This example shows how to encapsulate sate in dioxus components with the reducer pattern. //! This example shows how to encapsulate state in dioxus components with the reducer pattern.
//! This pattern is very useful when a single component can handle many types of input that can //! This pattern is very useful when a single component can handle many types of input that can
//! be represented by an enum. //! be represented by an enum.

View file

@ -43,7 +43,7 @@ fn main() {
} }
/// When trying to return "nothing" to Dioxus, you'll need to specify the type parameter or Rust will be sad. /// When trying to return "nothing" to Dioxus, you'll need to specify the type parameter or Rust will be sad.
/// This type alias specifices the type for you so you don't need to write "None as Option<()>" /// This type alias specifies the type for you so you don't need to write "None as Option<()>"
const NONE_ELEMENT: Option<()> = None; const NONE_ELEMENT: Option<()> = None;
use baller::Baller; use baller::Baller;
@ -104,7 +104,7 @@ pub static Example: FC<()> = |(cx, props)| {
// Matching // Matching
// Matching will throw a Rust error about "no two closures are the same type" // Matching will throw a Rust error about "no two closures are the same type"
// To fix this, call "render" method or use the "in" syntax to produce VNodes. // 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) // There's nothing we can do about it, sorry :/ (unless you want *really* unhygienic macros)
{match true { {match true {
true => rsx!(cx, h1 {"Top text"}), true => rsx!(cx, h1 {"Top text"}),
false => cx.render(rsx!( h1 {"Bottom text"})) false => cx.render(rsx!( h1 {"Bottom text"}))

View file

@ -4,7 +4,7 @@
//! //!
//! This example shows how to use the dioxus_desktop crate to build a basic desktop application. //! 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 //! Under the hood, the dioxus_desktop crate bridges a native Dioxus VirtualDom with a custom prebuilt application running
//! in the webview runtime. Custom handlers are provided for the webview instance to consume patches and emit user events //! in the webview runtime. Custom handlers are provided for the webview instance to consume patches and emit user events
//! into the native VDom instance. //! into the native VDom instance.
//! //!

View file

@ -4,7 +4,7 @@
//! //!
//! This example shows how to use the dioxus_desktop crate to build a basic desktop application. //! 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 //! Under the hood, the dioxus_desktop crate bridges a native Dioxus VirtualDom with a custom prebuilt application running
//! in the webview runtime. Custom handlers are provided for the webview instance to consume patches and emit user events //! in the webview runtime. Custom handlers are provided for the webview instance to consume patches and emit user events
//! into the native VDom instance. //! into the native VDom instance.
//! //!

View file

@ -2,7 +2,7 @@
Welcome to the first iteration of the Dioxus Virtual DOM! This release brings support for: Welcome to the first iteration of the Dioxus Virtual DOM! This release brings support for:
- Web via WASM - Web via Wasm
- Desktop via webview integration - Desktop via webview integration
- Server-rendering with custom ToString implementation - Server-rendering with custom ToString implementation
- State management - State management

View file

@ -422,7 +422,7 @@ refs only work when you're native to the platform. it doesn't make sense to gain
React makes refs - and protection against dom manipulation - work by modifying the real dom while diffing the virtual dom. This lets it bind real dom elements to the virtual dom elements. Dioxus currently does not do this, instead creating a list of changes for an interpreter to apply once diffing has completed. React makes refs - and protection against dom manipulation - work by modifying the real dom while diffing the virtual dom. This lets it bind real dom elements to the virtual dom elements. Dioxus currently does not do this, instead creating a list of changes for an interpreter to apply once diffing has completed.
This behavior fit dodrio well as all dom manipulations would occur batched. The original intention for this approach was to make it faster to read out of wasm and into JS. Dodrio is essentially performing the wasm job that wasm<->js for strings does. In theory, this particular optimization is not necessary. This behavior fit dodrio well as all dom manipulations would occur batched. The original intention for this approach was to make it faster to read out of Wasm and into JS. Dodrio is essentially performing the Wasm job that Wasm<->JS for strings does. In theory, this particular optimization is not necessary.
https://github.com/fitzgen/dodrio/issues/77 https://github.com/fitzgen/dodrio/issues/77

View file

@ -26,13 +26,13 @@ Dioxus-core leverages some really cool techniques and hits a very high level of
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. 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. 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.
## Goals ## Goals
We have big goals for Dioxus. The final implementation must: We have big goals for Dioxus. The final implementation must:
- Be **fast**. Allocators are typically slow in WASM/Rust, so we should have a smart way of allocating. - Be **fast**. Allocators are typically slow in Wasm/Rust, so we should have a smart way of allocating.
- Be extremely memory efficient. Servers should handle tens of thousands of simultaneous VDoms with no problem. - Be extremely memory efficient. Servers should handle tens of thousands of simultaneous VDoms with no problem.
- Be concurrent. Components should be able to pause rendering using a threading mechanism. - Be concurrent. Components should be able to pause rendering using a threading mechanism.
- Be "remote". Edit lists should be separate from the Renderer implementation. - Be "remote". Edit lists should be separate from the Renderer implementation.

View file

@ -7,7 +7,7 @@ use crate::innerlude::*;
pub(crate) struct RealChildIterator<'a> { pub(crate) struct RealChildIterator<'a> {
scopes: &'a ResourcePool, scopes: &'a ResourcePool,
// Heuristcally we should never bleed into 4 completely nested fragments/components // Heuristically we should never bleed into 4 completely nested fragments/components
// Smallvec lets us stack allocate our little stack machine so the vast majority of cases are sane // Smallvec lets us stack allocate our little stack machine so the vast majority of cases are sane
// TODO: use const generics instead of the 4 estimation // TODO: use const generics instead of the 4 estimation
stack: smallvec::SmallVec<[(u16, &'a VNode<'a>); 4]>, stack: smallvec::SmallVec<[(u16, &'a VNode<'a>); 4]>,

View file

@ -2,7 +2,7 @@
//! for components to be used within Nodes. //! for components to be used within Nodes.
//! //!
//! Note - using the builder pattern does not required the Properties trait to be implemented - the only thing that matters is //! Note - using the builder pattern does not required the Properties trait to be implemented - the only thing that matters is
//! if the type suppports PartialEq. The Properties trait is used by the rsx! and html! macros to generate the type-safe builder //! if the type supports PartialEq. The Properties trait is used by the rsx! and html! macros to generate the type-safe builder
//! that ensures compile-time required and optional fields on cx. //! that ensures compile-time required and optional fields on cx.
use crate::innerlude::{Context, DomTree, LazyNodes, FC}; use crate::innerlude::{Context, DomTree, LazyNodes, FC};
@ -108,7 +108,7 @@ pub trait Properties: Sized {
/// ///
/// # Safety /// # Safety
/// The user must know if their props are static, but if they make a mistake, UB happens /// The user must know if their props are static, but if they make a mistake, UB happens
/// Therefore it's unsafe to memeoize. /// Therefore it's unsafe to memoize.
unsafe fn memoize(&self, other: &Self) -> bool; unsafe fn memoize(&self, other: &Self) -> bool;
} }

View file

@ -203,7 +203,7 @@ impl<'src> Context<'src> {
.flatten(); .flatten();
} }
/// Try to retrive a SharedState with type T from the any parent Scope. /// Try to retrieve a SharedState with type T from the any parent Scope.
pub fn consume_state<T: 'static>(self) -> Option<Rc<T>> { pub fn consume_state<T: 'static>(self) -> Option<Rc<T>> {
let getter = &self.scope.shared.get_shared_context; let getter = &self.scope.shared.get_shared_context;
let ty = TypeId::of::<T>(); let ty = TypeId::of::<T>();
@ -298,9 +298,9 @@ impl<'src> Context<'src> {
} }
const HOOK_ERR_MSG: &str = r###" const HOOK_ERR_MSG: &str = r###"
Unable to retrive the hook that was initialized in this index. Unable to retrieve the hook that was initialized at this index.
Consult the `rules of hooks` to understand how to use hooks properly. Consult the `rules of hooks` to understand how to use hooks properly.
You likely used the hook in a conditional. Hooks rely on consistent ordering between renders. You likely used the hook in a conditional. Hooks rely on consistent ordering between renders.
Any function prefixed with "use" should not be called conditionally. Functions prefixed with "use" should never be called conditionally.
"###; "###;

View file

@ -6,7 +6,7 @@
//! ## Notice: //! ## Notice:
//! //!
//! The inspiration and code for this module was originally taken from Dodrio (@fitzgen) and then modified to support //! The inspiration and code for this module was originally taken from Dodrio (@fitzgen) and then modified to support
//! Components, Fragments, Suspense, SubTree memoization, incremental diffing, cancelation, NodeRefs, pausing, priority //! Components, Fragments, Suspense, SubTree memoization, incremental diffing, cancellation, NodeRefs, pausing, priority
//! scheduling, and additional batching operations. //! scheduling, and additional batching operations.
//! //!
//! ## Implementation Details: //! ## Implementation Details:
@ -15,8 +15,8 @@
//! -------------------- //! --------------------
//! All nodes are addressed by their IDs. The RealDom provides an imperative interface for making changes to these nodes. //! All nodes are addressed by their IDs. The RealDom provides an imperative interface for making changes to these nodes.
//! We don't necessarily require that DOM changes happen instantly during the diffing process, so the implementor may choose //! We don't necessarily require that DOM changes happen instantly during the diffing process, so the implementor may choose
//! to batch nodes if it is more performant for their application. The element IDs are indicies into the internal element //! to batch nodes if it is more performant for their application. The element IDs are indices into the internal element
//! array. The expectation is that implemenetors will use the ID as an index into a Vec of real nodes, allowing for passive //! array. The expectation is that implementors will use the ID as an index into a Vec of real nodes, allowing for passive
//! garbage collection as the VirtualDOM replaces old nodes. //! garbage collection as the VirtualDOM replaces old nodes.
//! //!
//! When new vnodes are created through `cx.render`, they won't know which real node they correspond to. During diffing, //! When new vnodes are created through `cx.render`, they won't know which real node they correspond to. During diffing,
@ -37,27 +37,27 @@
//! //!
//! ### Suspense //! ### Suspense
//! ------------ //! ------------
//! Dioxus implements suspense slightly differently than React. In React, each fiber is manually progressed until it runs //! Dioxus implements Suspense slightly differently than React. In React, each fiber is manually progressed until it runs
//! into a promise-like value. React will then work on the next "ready" fiber, checking back on the previous fiber once //! into a promise-like value. React will then work on the next "ready" fiber, checking back on the previous fiber once
//! it has finished its new work. In Dioxus, we use a similar approach, but try to completely render the tree before //! it has finished its new work. In Dioxus, we use a similar approach, but try to completely render the tree before
//! switching sub-fibers. Instead, each future is submitted into a futures-queue and the node is manually loaded later on. //! switching sub-fibers. Instead, each future is submitted into a futures-queue and the node is manually loaded later on.
//! Due to the frequent calls to "yield_now" we can get the pure "fetch-as-you-render" behavior of React fiber. //! Due to the frequent calls to "yield_now" we can get the pure "fetch-as-you-render" behavior of React Fiber.
//! //!
//! We're able to use this approach because we use placeholder nodes - futures that aren't ready still get submitted to //! We're able to use this approach because we use placeholder nodes - futures that aren't ready still get submitted to
//! DOM, but as a placeholder. //! DOM, but as a placeholder.
//! //!
//! Right now, the "suspense" queue is intertwined the hooks. In the future, we should allow any future to drive attributes //! Right now, the "suspense" queue is intertwined with hooks. In the future, we should allow any future to drive attributes
//! and contents, without the need for the "use_suspense" hook. In the interim, this is the quickest way to get suspense working. //! and contents, without the need for the "use_suspense" hook. In the interim, this is the quickest way to get Suspense working.
//! //!
//! ## Subtree Memoization //! ## Subtree Memoization
//! ----------------------- //! -----------------------
//! We also employ "subtree memoization" which saves us from having to check trees which take no dynamic content. We can //! We also employ "subtree memoization" which saves us from having to check trees which hold no dynamic content. We can
//! detect if a subtree is "static" by checking if its children are "static". Since we dive into the tree depth-first, the //! detect if a subtree is "static" by checking if its children are "static". Since we dive into the tree depth-first, the
//! calls to "create" propogate this information upwards. Structures like the one below are entirely static: //! calls to "create" propagate this information upwards. Structures like the one below are entirely static:
//! ```rust //! ```rust
//! rsx!( div { class: "hello world", "this node is entirely static" } ) //! rsx!( div { class: "hello world", "this node is entirely static" } )
//! ``` //! ```
//! Because the subtrees won't be diffed, their "real node" data will be stale (invalid), so its up to the reconciler to //! Because the subtrees won't be diffed, their "real node" data will be stale (invalid), so it's up to the reconciler to
//! track nodes created in a scope and clean up all relevant data. Support for this is currently WIP and depends on comp-time //! track nodes created in a scope and clean up all relevant data. Support for this is currently WIP and depends on comp-time
//! hashing of the subtree from the rsx! macro. We do a very limited form of static analysis via static string pointers as //! hashing of the subtree from the rsx! macro. We do a very limited form of static analysis via static string pointers as
//! a way of short-circuiting the most expensive checks. //! a way of short-circuiting the most expensive checks.
@ -70,11 +70,11 @@
//! //!
//! ## Garbage Collection //! ## Garbage Collection
//! --------------------- //! ---------------------
//! Dioxus uses a passive garbage collection system to clean up old nodes once the work has been completed. This garabge //! Dioxus uses a passive garbage collection system to clean up old nodes once the work has been completed. This garbage
//! collection is done internally once the main diffing work is complete. After the "garbage" is collected, Dioxus will then //! collection is done internally once the main diffing work is complete. After the "garbage" is collected, Dioxus will then
//! start to re-use old keys for new nodes. This results in a passive memory management system that is very efficient. //! start to re-use old keys for new nodes. This results in a passive memory management system that is very efficient.
//! //!
//! The IDs used by the key/map are just an index into a vec. This means that Dioxus will drive the key allocation strategy //! The IDs used by the key/map are just an index into a Vec. This means that Dioxus will drive the key allocation strategy
//! so the client only needs to maintain a simple list of nodes. By default, Dioxus will not manually clean up old nodes //! so the client only needs to maintain a simple list of nodes. By default, Dioxus will not manually clean up old nodes
//! for the client. As new nodes are created, old nodes will be over-written. //! for the client. As new nodes are created, old nodes will be over-written.
//! //!
@ -95,7 +95,7 @@ use DomEdit::*;
/// Our DiffMachine is an iterative tree differ. /// Our DiffMachine is an iterative tree differ.
/// ///
/// It uses techniques of a stack machine to allow pausing and restarting of the diff algorithm. This /// It uses techniques of a stack machine to allow pausing and restarting of the diff algorithm. This
/// was origially implemented using recursive techniques, but Rust lacks the abilty to call async functions recursively, /// was originally implemented using recursive techniques, but Rust lacks the ability to call async functions recursively,
/// meaning we could not "pause" the original diffing algorithm. /// meaning we could not "pause" the original diffing algorithm.
/// ///
/// Instead, we use a traditional stack machine approach to diff and create new nodes. The diff algorithm periodically /// Instead, we use a traditional stack machine approach to diff and create new nodes. The diff algorithm periodically
@ -194,7 +194,7 @@ impl<'bump> DiffMachine<'bump> {
}; };
if deadline_expired() { if deadline_expired() {
log::debug!("Deadling expired before we could finished!"); log::debug!("Deadline expired before we could finished!");
return false; return false;
} }
} }
@ -587,7 +587,7 @@ impl<'bump> DiffMachine<'bump> {
} }
// ============================================= // =============================================
// Utilites for creating new diff instructions // Utilities for creating new diff instructions
// ============================================= // =============================================
// Diff the given set of old and new children. // Diff the given set of old and new children.
@ -603,7 +603,7 @@ impl<'bump> DiffMachine<'bump> {
// //
// Remember, non-empty lists does not mean that there are real elements, just that there are virtual elements. // Remember, non-empty lists does not mean that there are real elements, just that there are virtual elements.
// //
// Frament nodes cannot generate empty children lists, so we can assume that when a list is empty, it belongs only // Fragment nodes cannot generate empty children lists, so we can assume that when a list is empty, it belongs only
// to an element, and appending makes sense. // to an element, and appending makes sense.
fn diff_children(&mut self, old: &'bump [VNode<'bump>], new: &'bump [VNode<'bump>]) { fn diff_children(&mut self, old: &'bump [VNode<'bump>], new: &'bump [VNode<'bump>]) {
// Remember, fragments can never be empty (they always have a single child) // Remember, fragments can never be empty (they always have a single child)
@ -753,7 +753,7 @@ impl<'bump> DiffMachine<'bump> {
self.remove_nodes(old_middle); self.remove_nodes(old_middle);
} else if old_middle.is_empty() { } else if old_middle.is_empty() {
// there were no old elements, so just create the new elements // there were no old elements, so just create the new elements
// we need to find the right "foothold" though - we shouldnt use the "append" at all // we need to find the right "foothold" though - we shouldn't use the "append" at all
if left_offset == 0 { if left_offset == 0 {
// insert at the beginning of the old list // insert at the beginning of the old list
let foothold = &old[old.len() - right_offset]; let foothold = &old[old.len() - right_offset];
@ -858,7 +858,7 @@ impl<'bump> DiffMachine<'bump> {
// Upon exit from this function, it will be restored to that same state. // Upon exit from this function, it will be restored to that same state.
fn diff_keyed_middle(&mut self, old: &'bump [VNode<'bump>], new: &'bump [VNode<'bump>]) { fn diff_keyed_middle(&mut self, old: &'bump [VNode<'bump>], new: &'bump [VNode<'bump>]) {
/* /*
1. Map the old keys into a numerical ordering based on indicies. 1. Map the old keys into a numerical ordering based on indices.
2. Create a map of old key to its index 2. Create a map of old key to its index
3. Map each new key to the old key, carrying over the old index. 3. Map each new key to the old key, carrying over the old index.
- IE if we have ABCD becomes BACD, our sequence would be 1,0,2,3 - IE if we have ABCD becomes BACD, our sequence would be 1,0,2,3
@ -884,7 +884,7 @@ impl<'bump> DiffMachine<'bump> {
debug_assert_ne!(new.first().map(|n| n.key()), old.first().map(|o| o.key())); debug_assert_ne!(new.first().map(|n| n.key()), old.first().map(|o| o.key()));
debug_assert_ne!(new.last().map(|n| n.key()), old.last().map(|o| o.key())); debug_assert_ne!(new.last().map(|n| n.key()), old.last().map(|o| o.key()));
// 1. Map the old keys into a numerical ordering based on indicies. // 1. Map the old keys into a numerical ordering based on indices.
// 2. Create a map of old key to its index // 2. Create a map of old key to its index
// IE if the keys were A B C, then we would have (A, 1) (B, 2) (C, 3). // IE if the keys were A B C, then we would have (A, 1) (B, 2) (C, 3).
let old_key_to_old_index = old let old_key_to_old_index = old
@ -952,7 +952,7 @@ impl<'bump> DiffMachine<'bump> {
if old_index == u32::MAX as usize { if old_index == u32::MAX as usize {
stack.create_node(new_node, MountType::Absorb); stack.create_node(new_node, MountType::Absorb);
} else { } else {
// this funciton should never take LIS indicies // this function should never take LIS indices
stack.push(DiffInstruction::PrepareMove { node: new_node }); stack.push(DiffInstruction::PrepareMove { node: new_node });
stack.push(DiffInstruction::Diff { stack.push(DiffInstruction::Diff {
new: new_node, new: new_node,

View file

@ -111,7 +111,7 @@ impl<'bump> DiffStack<'bump> {
self.instructions.push(DiffInstruction::PopScope); self.instructions.push(DiffInstruction::PopScope);
// Run the creation algorithm with this scope on the stack // Run the creation algorithm with this scope on the stack
// ?? I think we treat components as framgnets?? // ?? I think we treat components as fragments??
self.instructions.push(DiffInstruction::Create { node }); self.instructions.push(DiffInstruction::Create { node });
} }
} }

View file

@ -35,7 +35,7 @@ pub struct UserEvent {
/// Priority of Event Triggers. /// Priority of Event Triggers.
/// ///
/// Internally, Dioxus will abort work that's taking too long if new, more important, work arrives. Unlike React, Dioxus /// Internally, Dioxus will abort work that's taking too long if new, more important work arrives. Unlike React, Dioxus
/// won't be afraid to pause work or flush changes to the RealDOM. This is called "cooperative scheduling". Some Renderers /// won't be afraid to pause work or flush changes to the RealDOM. This is called "cooperative scheduling". Some Renderers
/// implement this form of scheduling internally, however Dioxus will perform its own scheduling as well. /// implement this form of scheduling internally, however Dioxus will perform its own scheduling as well.
/// ///
@ -69,17 +69,17 @@ pub enum EventPriority {
High = 2, High = 2,
/// "Medium priority" work is generated by page events not triggered by the user. These types of events are less important /// "Medium priority" work is generated by page events not triggered by the user. These types of events are less important
/// than "High Priority" events and will take presedence over low priority events. /// than "High Priority" events and will take precedence over low priority events.
/// ///
/// This is typically reserved for VirtualEvents that are not related to keyboard or mouse input. /// This is typically reserved for VirtualEvents that are not related to keyboard or mouse input.
/// ///
/// React calls these "continuous" events (e.g. mouse move, mouse wheel, touch move, etc). /// React calls these "continuous" events (e.g. mouse move, mouse wheel, touch move, etc).
Medium = 1, Medium = 1,
/// "Low Priority" work will always be pre-empted unless the work is significantly delayed, in which case it will be /// "Low Priority" work will always be preempted unless the work is significantly delayed, in which case it will be
/// advanced to the front of the work queue until completed. /// advanced to the front of the work queue until completed.
/// ///
/// The primary user of Low Priority work is the asynchronous work system (suspense). /// The primary user of Low Priority work is the asynchronous work system (Suspense).
/// ///
/// This is considered "idle" work or "background" work. /// This is considered "idle" work or "background" work.
Low = 0, Low = 0,

View file

@ -6,9 +6,9 @@ use crate::FC;
/// Provides heuristics to the "SharedResources" object for improving allocation performance. /// Provides heuristics to the "SharedResources" object for improving allocation performance.
/// ///
/// This heueristic engine records the memory footprint of bump arenas and hook lists for each component. These records are /// This heuristics engine records the memory footprint of bump arenas and hook lists for each component. These records are
/// then used later on to optimize the initial allocation for future components. This helps save large allocations later on /// then used later on to optimize the initial allocation for future components. This helps save large allocations later on
/// that would slow down the diffing and initializion process. /// that would slow down the diffing and initialization process.
/// ///
/// ///
pub struct HeuristicsEngine { pub struct HeuristicsEngine {

View file

@ -30,10 +30,10 @@ impl HookList {
/// This resets the internal iterator count /// This resets the internal iterator count
/// It's okay that we've given out each hook, but now we have the opportunity to give it out again /// It's okay that we've given out each hook, but now we have the opportunity to give it out again
/// Therefore, resetting is cosudered unsafe /// Therefore, resetting is considered unsafe
/// ///
/// This should only be ran by Dioxus itself before "running scope". /// This should only be ran by Dioxus itself before "running scope".
/// Dioxus knows how to descened through the tree to prevent mutable aliasing. /// Dioxus knows how to descend through the tree to prevent mutable aliasing.
pub(crate) unsafe fn reset(&mut self) { pub(crate) unsafe fn reset(&mut self) {
self.idx.set(0); self.idx.set(0);
} }

View file

@ -1,6 +1,6 @@
//! Built-in hooks //! Built-in hooks
//! //!
//! This module contains all the low-level built-in hooks that require 1st party support to work. //! This module contains all the low-level built-in hooks that require first party support to work.
//! //!
//! Hooks: //! Hooks:
//! - [`use_hook`] //! - [`use_hook`]

View file

@ -146,7 +146,7 @@ impl<'a> NodeRefMutation<'a> {
} }
} }
/// A `DomEdit` represents a serialzied form of the VirtualDom's trait-based API. This allows streaming edits across the /// A `DomEdit` represents a serialized form of the VirtualDom's trait-based API. This allows streaming edits across the
/// network or through FFI boundaries. /// network or through FFI boundaries.
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
#[cfg_attr( #[cfg_attr(
@ -164,7 +164,7 @@ pub enum DomEdit<'bump> {
many: u32, many: u32,
}, },
// "Root" refers to the item direclty // "Root" refers to the item directly
// it's a waste of an instruction to push the root directly // it's a waste of an instruction to push the root directly
ReplaceWith { ReplaceWith {
root: u64, root: u64,

View file

@ -15,7 +15,7 @@ use std::{
/// A composable "VirtualNode" to declare a User Interface in the Dioxus VirtualDOM. /// A composable "VirtualNode" to declare a User Interface in the Dioxus VirtualDOM.
/// ///
/// VNodes are designed to be lightweight and used with with a bump alloactor. To create a VNode, you can use either of: /// VNodes are designed to be lightweight and used with with a bump allocator. To create a VNode, you can use either of:
/// - the [`rsx`] macro /// - the [`rsx`] macro
/// - the [`html`] macro /// - the [`html`] macro
/// - the [`NodeFactory`] API /// - the [`NodeFactory`] API
@ -159,7 +159,7 @@ pub struct VAnchor {
pub dom_id: Cell<Option<ElementId>>, pub dom_id: Cell<Option<ElementId>>,
} }
/// A bump-alloacted string slice and metadata. /// A bump-allocated string slice and metadata.
pub struct VText<'src> { pub struct VText<'src> {
pub text: &'src str, pub text: &'src str,
@ -589,7 +589,7 @@ impl<'a> NodeFactory<'a> {
/// impl IntoIterator<Item = impl IntoVNode<'a>> /// impl IntoIterator<Item = impl IntoVNode<'a>>
/// ``` /// ```
/// ///
/// As such, all node creation must go through the factory, which is only availble in the component context. /// As such, all node creation must go through the factory, which is only available in the component context.
/// These strict requirements make it possible to manage lifetimes and state. /// These strict requirements make it possible to manage lifetimes and state.
pub trait IntoVNode<'a> { pub trait IntoVNode<'a> {
fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a>; fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a>;

View file

@ -8,7 +8,7 @@ pub(crate) struct ResourcePool {
This *has* to be an UnsafeCell. This *has* to be an UnsafeCell.
Each BumpFrame and Scope is located in this Slab - and we'll need mutable access to a scope while holding on to Each BumpFrame and Scope is located in this Slab - and we'll need mutable access to a scope while holding on to
its bumpframe conents immutably. its bumpframe contents immutably.
However, all of the interaction with this Slab is done in this module and the Diff module, so it should be fairly However, all of the interaction with this Slab is done in this module and the Diff module, so it should be fairly
simple to audit. simple to audit.

View file

@ -43,19 +43,19 @@ before the timeout, then Dioxus will work on any pending work in the interim. If
are committed, and coroutines are polled during the idle period. However, if the timeout expires, then the DiffMachine are committed, and coroutines are polled during the idle period. However, if the timeout expires, then the DiffMachine
future is paused and saved (self-referentially). future is paused and saved (self-referentially).
# Priorty System # Priority System
So far, we've been able to thread our Dioxus work between animation frames - the main thread is not blocked! But that So far, we've been able to thread our Dioxus work between animation frames - the main thread is not blocked! But that
doesn't help us _under load_. How do we still stay snappy... even if we're doing a lot of work? Well, that's where doesn't help us _under load_. How do we still stay snappy... even if we're doing a lot of work? Well, that's where
priorities come into play. The goal with priorities is to schedule shorter work as a "high" priority and longer work as priorities come into play. The goal with priorities is to schedule shorter work as a "high" priority and longer work as
a "lower" priority. That way, we can interrupt long-running low-prioty work with short-running high-priority work. a "lower" priority. That way, we can interrupt long-running low-priority work with short-running high-priority work.
React's priority system is quite complex. React's priority system is quite complex.
There are 5 levels of priority and 2 distinctions between UI events (discrete, continuous). I believe React really only There are 5 levels of priority and 2 distinctions between UI events (discrete, continuous). I believe React really only
uses 3 priority levels and "idle" priority isn't used... Regardless, there's some batching going on. uses 3 priority levels and "idle" priority isn't used... Regardless, there's some batching going on.
For Dioxus, we're going with a 4 tier priorty system: For Dioxus, we're going with a 4 tier priority system:
- Sync: Things that need to be done by the next frame, like TextInput on controlled elements - Sync: Things that need to be done by the next frame, like TextInput on controlled elements
- High: for events that block all others - clicks, keyboard, and hovers - High: for events that block all others - clicks, keyboard, and hovers
- Medium: for UI events caused by the user but not directly - scrolls/forms/focus (all other events) - Medium: for UI events caused by the user but not directly - scrolls/forms/focus (all other events)
@ -132,7 +132,7 @@ pub(crate) struct Scheduler {
/// A generational arena is used to re-use slots of deleted scopes without having to resize the underlying arena. /// A generational arena is used to re-use slots of deleted scopes without having to resize the underlying arena.
/// ///
/// This is wrapped in an UnsafeCell because we will need to get mutable access to unique values in unique bump arenas /// This is wrapped in an UnsafeCell because we will need to get mutable access to unique values in unique bump arenas
/// and rusts's guartnees cannot prove that this is safe. We will need to maintain the safety guarantees manually. /// and rusts's guarantees cannot prove that this is safe. We will need to maintain the safety guarantees manually.
pub pool: ResourcePool, pub pool: ResourcePool,
pub heuristics: HeuristicsEngine, pub heuristics: HeuristicsEngine,
@ -187,7 +187,7 @@ impl Scheduler {
let sender = sender.clone(); let sender = sender.clone();
Rc::new(move |id| { Rc::new(move |id| {
// //
log::debug!("scheduling immedate! {:?}", id); log::debug!("scheduling immediate! {:?}", id);
sender.unbounded_send(SchedulerMsg::Immediate(id)).unwrap() sender.unbounded_send(SchedulerMsg::Immediate(id)).unwrap()
}) })
}, },
@ -387,7 +387,7 @@ impl Scheduler {
}); });
if let Some(scopeid) = self.dirty_scopes.pop() { if let Some(scopeid) = self.dirty_scopes.pop() {
log::info!("handlng dirty scope {:?}", scopeid); log::info!("handling dirty scope {:?}", scopeid);
if !ran_scopes.contains(&scopeid) { if !ran_scopes.contains(&scopeid) {
ran_scopes.insert(scopeid); ran_scopes.insert(scopeid);
log::debug!("about to run scope {:?}", scopeid); log::debug!("about to run scope {:?}", scopeid);
@ -463,7 +463,7 @@ impl Scheduler {
- When called, check for any UI events that might've been received since the last frame. - When called, check for any UI events that might've been received since the last frame.
- Dump all UI events into a "pending discrete" queue and a "pending continuous" queue. - Dump all UI events into a "pending discrete" queue and a "pending continuous" queue.
- If there are any pending discrete events, then elevate our priorty level. If our priority level is already "high," - If there are any pending discrete events, then elevate our priority level. If our priority level is already "high,"
then we need to finish the high priority work first. If the current work is "low" then analyze what scopes then we need to finish the high priority work first. If the current work is "low" then analyze what scopes
will be invalidated by this new work. If this interferes with any in-flight medium or low work, then we need will be invalidated by this new work. If this interferes with any in-flight medium or low work, then we need
to bump the other work out of the way, or choose to process it so we don't have any conflicts. to bump the other work out of the way, or choose to process it so we don't have any conflicts.
@ -583,7 +583,7 @@ impl Scheduler {
} else { } else {
// todo: should this be a hard error? // todo: should this be a hard error?
log::warn!( log::warn!(
"Component failed to run succesfully during rebuild. "Component failed to run successfully during rebuild.
This does not result in a failed rebuild, but indicates a logic failure within your app." This does not result in a failed rebuild, but indicates a logic failure within your app."
); );
} }

View file

@ -231,20 +231,20 @@ impl Scope {
} }
/// This method cleans up any references to data held within our hook list. This prevents mutable aliasing from /// This method cleans up any references to data held within our hook list. This prevents mutable aliasing from
/// causuing UB in our tree. /// causing UB in our tree.
/// ///
/// This works by cleaning up our references from the bottom of the tree to the top. The directed graph of components /// This works by cleaning up our references from the bottom of the tree to the top. The directed graph of components
/// essentially forms a dependency tree that we can traverse from the bottom to the top. As we traverse, we remove /// essentially forms a dependency tree that we can traverse from the bottom to the top. As we traverse, we remove
/// any possible references to the data in the hook list. /// any possible references to the data in the hook list.
/// ///
/// Refrences to hook data can only be stored in listeners and component props. During diffing, we make sure to log /// References to hook data can only be stored in listeners and component props. During diffing, we make sure to log
/// all listeners and borrowed props so we can clear them here. /// all listeners and borrowed props so we can clear them here.
/// ///
/// This also makes sure that drop order is consistent and predictable. All resources that rely on being dropped will /// This also makes sure that drop order is consistent and predictable. All resources that rely on being dropped will
/// be dropped. /// be dropped.
pub(crate) fn ensure_drop_safety(&mut self, pool: &ResourcePool) { pub(crate) fn ensure_drop_safety(&mut self, pool: &ResourcePool) {
// make sure we drop all borrowed props manually to guarantee that their drop implementation is called before we // make sure we drop all borrowed props manually to guarantee that their drop implementation is called before we
// run the hooks (which hold an &mut Referrence) // run the hooks (which hold an &mut Reference)
// right now, we don't drop // right now, we don't drop
self.borrowed_props self.borrowed_props
.get_mut() .get_mut()

View file

@ -11,10 +11,10 @@
//! //!
//! Included is: //! Included is:
//! - The [`VirtualDom`] itself //! - The [`VirtualDom`] itself
//! - The [`Scope`] object for mangning component lifecycle //! - The [`Scope`] object for managing component lifecycle
//! - The [`ActiveFrame`] object for managing the Scope`s microheap //! - The [`ActiveFrame`] object for managing the Scope`s microheap
//! - The [`Context`] object for exposing VirtualDOM API to components //! - The [`Context`] object for exposing VirtualDOM API to components
//! - The [`NodeFactory`] object for lazyily exposing the `Context` API to the nodebuilder API //! - The [`NodeFactory`] object for lazily exposing the `Context` API to the nodebuilder API
//! //!
//! This module includes just the barebones for a complete VirtualDOM API. //! This module includes just the barebones for a complete VirtualDOM API.
//! Additional functionality is defined in the respective files. //! Additional functionality is defined in the respective files.
@ -130,7 +130,7 @@ impl VirtualDom {
/// Launch the VirtualDom, but provide your own channel for receiving and sending messages into the scheduler. /// Launch the VirtualDom, but provide your own channel for receiving and sending messages into the scheduler.
/// ///
/// This is useful when the VirtualDom must be driven from outside a thread and it doesn't make sense to wait for the /// This is useful when the VirtualDom must be driven from outside a thread and it doesn't make sense to wait for the
/// VirtualDom to be created just to retrive its channel receiver. /// VirtualDom to be created just to retrieve its channel receiver.
pub fn new_with_props_and_scheduler<P: 'static + Send>( pub fn new_with_props_and_scheduler<P: 'static + Send>(
root: FC<P>, root: FC<P>,
root_props: P, root_props: P,
@ -173,7 +173,7 @@ impl VirtualDom {
/// Get the [`Scope`] for the root component. /// Get the [`Scope`] for the root component.
/// ///
/// This is useful for traversing the tree from the root for heuristics or altnerative renderers that use Dioxus /// This is useful for traversing the tree from the root for heuristics or alternsative renderers that use Dioxus
/// directly. /// directly.
pub fn base_scope(&self) -> &Scope { pub fn base_scope(&self) -> &Scope {
self.scheduler.pool.get_scope(self.base_scope).unwrap() self.scheduler.pool.get_scope(self.base_scope).unwrap()
@ -186,7 +186,7 @@ impl VirtualDom {
/// Update the root props of this VirtualDOM. /// Update the root props of this VirtualDOM.
/// ///
/// This method retuns None if the old props could not be removed. The entire VirtualDOM will be rebuilt immediately, /// This method returns None if the old props could not be removed. The entire VirtualDOM will be rebuilt immediately,
/// so calling this method will block the main thread until computation is done. /// so calling this method will block the main thread until computation is done.
/// ///
/// ## Example /// ## Example
@ -258,7 +258,7 @@ impl VirtualDom {
/// Compute a manual diff of the VirtualDOM between states. /// Compute a manual diff of the VirtualDOM between states.
/// ///
/// This can be useful when state inside the DOM is remotely changed from the outside, but not propogated as an event. /// This can be useful when state inside the DOM is remotely changed from the outside, but not propagated as an event.
/// ///
/// In this case, every component will be diffed, even if their props are memoized. This method is intended to be used /// In this case, every component will be diffed, even if their props are memoized. This method is intended to be used
/// to force an update of the DOM when the state of the app is changed outside of the app. /// to force an update of the DOM when the state of the app is changed outside of the app.

View file

@ -2,14 +2,14 @@
//! --------------------- //! ---------------------
//! //!
//! This example shows what *not* to do and provides a reason why a given pattern is considered an "AntiPattern". Most //! This example shows what *not* to do and provides a reason why a given pattern is considered an "AntiPattern". Most
//! anti-patterns are considered wrong to due performance reasons or violate the "rules" of Dioxus. These rules are //! anti-patterns are considered wrong due performance reasons or violate the "rules" of Dioxus. These rules are
//! borrowed from other successful UI frameworks, and Dioxus is more focused on providing a familiar, ergonomic interface //! borrowed from other successful UI frameworks, and Dioxus is more focused on providing a familiar, ergonomic interface
//! rather than building new harder-to-misuse patterns. //! rather than building new harder-to-misuse patterns.
//! //!
//! In this list we showcase: //! In this list we showcase:
//! - Not adding keys for iterators //! - Not adding keys for iterators
//! - Heavily nested fragments //! - Heavily nested fragments
//! - Understadning ordering of set_state //! - Understanding ordering of set_state
//! - Naming conventions //! - Naming conventions
//! - Rules of hooks //! - Rules of hooks
//! //!
@ -21,7 +21,7 @@ use dioxus::prelude::*;
/// ///
/// This is considered an anti-pattern for performance reasons. Dioxus will diff your current and old layout and must /// This is considered an anti-pattern for performance reasons. Dioxus will diff your current and old layout and must
/// take a slower path if it can't correlate old elements with new elements. Lists are particularly susceptible to the /// take a slower path if it can't correlate old elements with new elements. Lists are particularly susceptible to the
/// "slow" path, so you're strongly encouraged to provide a unique ID stable between renders. Additionally, providing /// "slow" path, so you're strongly encouraged to provide a unique, stable ID between renders. Additionally, providing
/// the *wrong* keys is even worse - props might be assigned to the wrong components! Keys should be: /// the *wrong* keys is even worse - props might be assigned to the wrong components! Keys should be:
/// - Unique /// - Unique
/// - Stable /// - Stable
@ -47,10 +47,10 @@ static AntipatternNoKeys: FC<NoKeysProps> = |(cx, props)| {
/// ------------------------------------ /// ------------------------------------
/// ///
/// This particular antipattern is not necessarily an antipattern in other frameworks but does has a performance impact /// This particular antipattern is not necessarily an antipattern in other frameworks but does has a performance impact
/// in Dioxus apps. Fragments don't mount a physical element to the dom immediately, so Dioxus must recurse into its /// in Dioxus apps. Fragments don't mount a physical element to the DOM immediately, so Dioxus must recurse into its
/// children to find a physical dom node. This process is called "normalization". Other frameworks perform an agressive /// children to find a physical DOM node. This process is called "normalization". Other frameworks perform an agressive
/// mutative normalization while Dioxus keeps your VNodes immutable. This means that deepely nested fragments make Dioxus /// mutative normalization while Dioxus keeps your VNodes immutable. This means that deeply nested fragments make Dioxus
/// perform unnecessary work. Prefer one or two levels of fragments / nested components until presenting a true dom element. /// perform unnecessary work. Prefer one or two levels of fragments / nested components until presenting a true DOM element.
/// ///
/// Only Component and Fragment nodes are susceptible to this issue. Dioxus mitigates this with components by providing /// Only Component and Fragment nodes are susceptible to this issue. Dioxus mitigates this with components by providing
/// an API for registering shared state without the ContextProvider pattern. /// an API for registering shared state without the ContextProvider pattern.
@ -71,7 +71,7 @@ static AntipatternNestedFragments: FC<()> = |(cx, props)| {
) )
}; };
/// Antipattern: Using state after its been updated /// Antipattern: Using state after it's been updated
/// ----------------------------------------------- /// -----------------------------------------------
/// ///
/// This is an antipattern in other frameworks, but less so in Dioxus. However, it's important to highlight that use_state /// This is an antipattern in other frameworks, but less so in Dioxus. However, it's important to highlight that use_state
@ -82,7 +82,7 @@ static AntipatternNestedFragments: FC<()> = |(cx, props)| {
/// However, calling set_state will *not* update the current version of state in the component. This should be easy to /// However, calling set_state will *not* update the current version of state in the component. This should be easy to
/// recognize from the function signature, but Dioxus will not update the "live" version of state. Calling `set_state` /// recognize from the function signature, but Dioxus will not update the "live" version of state. Calling `set_state`
/// merely places a new value in the queue and schedules the component for a future update. /// merely places a new value in the queue and schedules the component for a future update.
static AntipaternRelyingOnSetState: FC<()> = |(cx, props)| { static AntipatternRelyingOnSetState: FC<()> = |(cx, props)| {
let (state, set_state) = use_state(cx, || "Hello world").classic(); let (state, set_state) = use_state(cx, || "Hello world").classic();
set_state("New state"); set_state("New state");
// This will return false! `state` will *still* be "Hello world" // This will return false! `state` will *still* be "Hello world"
@ -94,28 +94,28 @@ static AntipaternRelyingOnSetState: FC<()> = |(cx, props)| {
/// --------------------------- /// ---------------------------
/// ///
/// This antipattern is enforced to retain parity with other frameworks and provide useful IDE feedback, but is less /// This antipattern is enforced to retain parity with other frameworks and provide useful IDE feedback, but is less
/// critical than other potential misues. In short: /// critical than other potential misuses. In short:
/// - Only raw elements may start with a lowercase character /// - Only raw elements may start with a lowercase character
/// - All components must start with an uppercase character /// - All components must start with an uppercase character
/// ///
/// IE: the following component will be rejected when attempted to be used in the rsx! macro /// i.e.: the following component will be rejected when attempted to be used in the rsx! macro
static antipattern_component: FC<()> = |(cx, props)| todo!(); static antipattern_component: FC<()> = |(cx, props)| todo!();
/// Antipattern: Misusing hooks /// Antipattern: Misusing hooks
/// --------------------------- /// ---------------------------
/// ///
/// This pattern is an unfortunate one where Dioxus supports the same behavior as in other frameworks. Dioxus supports /// This pattern is an unfortunate one where Dioxus replicates the same behavior as other frameworks. Dioxus supports
/// "hooks" - IE "memory cells" that allow a value to be stored between renders. This allows other hooks to tap into /// "hooks" - i.e. "memory cells" that allow a value to be stored between renders. This allows other hooks to tap into
/// a components "memory" without explicitly adding all of its data to a struct definition. In Dioxus, hooks are allocated /// a component's "memory" without explicitly adding all of its data to a struct definition. In Dioxus, hooks are allocated
/// with a bump arena and then immediately sealed. /// with a bump arena and then immediately sealed.
/// ///
/// This means that hooks may not be misued: /// This means that hooks may not be misused:
/// - Called out of order /// - Called out of order
/// - Called in a conditional /// - Called in a conditional
/// - Called in loops or callbacks /// - Called in loops or callbacks
/// ///
/// For the most part, Rust helps with rule #3 but does not save you from misusing rule #1 or #2. Dioxus will panic /// For the most part, Rust helps with rule #3 but does not save you from misusing rule #1 or #2. Dioxus will panic
/// if hooks do not downcast the same data between renders. This is validated by TypeId - and eventually - a custom key. /// if hooks do not downcast to the same data between renders. This is validated by TypeId and, eventually, a custom key.
#[derive(PartialEq, Props)] #[derive(PartialEq, Props)]
struct MisuedHooksProps { struct MisuedHooksProps {
should_render_state: bool, should_render_state: bool,
@ -131,15 +131,15 @@ static AntipatternMisusedHooks: FC<MisuedHooksProps> = |(cx, props)| {
} }
}; };
/// Antipattern: Downcasting refs and panicing /// Antipattern: Downcasting refs and panicking
/// ------------------------------------------ /// ------------------------------------------
/// ///
/// Occassionally it's useful to get the ref of an element to handle it directly. Elements support downcasting to /// Occasionally it's useful to get the ref of an element to handle it directly. Elements support downcasting to
/// Dioxus's virtual element types as well as their true native counterparts. Downcasting to Dioxus' virtual elements /// Dioxus' virtual element types as well as their true native counterparts. Downcasting to Dioxus' virtual elements
/// will never panic, but downcasting to native elements will fail if on an unsupported platform. We recommend avoiding /// will never panic, but downcasting to native elements will fail if on an unsupported platform. We recommend avoiding
/// publishing hooks and components that deply rely on control over elements using their native `ref`, preferring to /// publishing hooks and components that deeply rely on controlling elements using their native `ref`, preferring to
/// use their Dioxus Virtual Element counterpart instead. /// use their Dioxus Virtual Element counterpart instead.
// This particular code *will panic* due to the unwrap. Try to avoid these types of patterns. /// This particular code *will panic* due to the unwrap. Try to avoid these types of patterns.
/// --------------------------------- /// ---------------------------------
/// TODO: Get this to compile properly /// TODO: Get this to compile properly
/// let div_ref = use_node_ref(&cx); /// let div_ref = use_node_ref(&cx);

View file

@ -29,7 +29,7 @@ static Greeting: FC<GreetingProps> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
div { div {
h1 { "Hello, {props.name}!" } h1 { "Hello, {props.name}!" }
p { "Welcome to the Diouxs framework" } p { "Welcome to the Dioxus framework" }
br {} br {}
{cx.children()} {cx.children()}
} }

View file

@ -1,14 +1,14 @@
//! Example: Children //! Example: Children
//! ----------------- //! -----------------
//! //!
//! Dioxus supports passing children in from the parent. These children are allocated in the parent and just forced //! Dioxus supports passing children in from the parent. These children are allocated in the parent and just passed
//! into the child. Components that pass in children may not be safely memoized, though in practice its rare for a //! into the child. Components that pass in children may not be safely memoized, though in practice it's rare for a
//! change in a parent to not result in a different set of children. //! change in a parent to not result in a different set of children.
//! //!
//! In Dioxus, children can *only be a list*. Unlike React, you cannot pass in functions or arbitrary data. This is //! In Dioxus, children can *only be a list*. Unlike React, you cannot pass in functions or arbitrary data. This is
//! partially a limitaiton in having static types, but is rather intentional to encourage the use of attributes where //! partially a limitation of having static types, but is rather intentional to encourage the use of attributes where
//! arbitrary child data might normally be used. Check out the `function driven children` example for how to adopt your //! arbitrary child data might normally be used. Check out the `function driven children` example for how to adopt your
//! React pattern for Dioxus' semantics. //! React pattern to Dioxus' semantics.
//! //!
//! Dioxus will let you use the `children` method more than once - and it's semantically *okay* - but you'll likely //! Dioxus will let you use the `children` method more than once - and it's semantically *okay* - but you'll likely
//! ruin your page if you try to clone elements in this way. Under the hood, Dioxus shares a "mounted ID" for each node, //! ruin your page if you try to clone elements in this way. Under the hood, Dioxus shares a "mounted ID" for each node,

View file

@ -3,10 +3,10 @@
//! //!
//! This example shows how to hide or show elements using conditional rendering. //! This example shows how to hide or show elements using conditional rendering.
//! //!
//! Often times you might want to display a different UI given some sort of condition. This is called "conditonal rendering". //! Oftentimes you might want to display a different UI given some sort of condition. This is called "conditional rendering".
//! In Dioxus, you can perform conditional rendering with optionals or matching. //! In Dioxus, you can perform conditional rendering with optionals or matching.
//! //!
//! The rsx! and html! macro accepts anything that is `IntoIter<Item = impl IntoVnode>`. Options and Results both implement //! The rsx! and html! macros accepts anything that is `IntoIter<Item = impl IntoVnode>`. Options and Results both implement
//! IntoIter for impl VNode, so you can use option/result for conditional rendering. //! IntoIter for impl VNode, so you can use option/result for conditional rendering.
use dioxus::prelude::*; use dioxus::prelude::*;
@ -58,7 +58,7 @@ pub static Example1: FC<MyProps1> = |(cx, props)| {
// or with optional chaining // or with optional chaining
{ {
props.should_show props.should_show
.then(|| rsx!(cx, div {"it is false!"})) .then(|| rsx!(cx, div {"it is true!"}))
.unwrap_or_else(|| rsx!(cx, div {"it is false!"})) .unwrap_or_else(|| rsx!(cx, div {"it is false!"}))
} }
} }

View file

@ -1,21 +1,21 @@
//! Example: Errror Handling //! Example: Error Handling
//! ------------------------ //! ------------------------
//! //!
//! Error handling in Dioxus comes in a few flavors. Because Dioxus is a Rust project, Options and Results are obviously //! Error handling in Dioxus comes in a few flavors. Because Dioxus is a Rust project, Options and Results are obviously
//! the go-to way of wrapping possibly-errored data. However, if a component fails to "unwrapping," everything will crash, //! the go-to way of wrapping possibly-errored data. However, if a component fails when "unwrapping," everything will crash,
//! the page will deadlock, and your users will be sad. //! the page will deadlock, and your users will be sad.
//! //!
//! So, obviously, you need to handle your errors. //! So, obviously, you need to handle your errors.
//! //!
//! Fortunately, it's easy to avoid panics, even during quick prototyping. //! Fortunately, it's easy to avoid panics, even during quick prototyping.
//! //!
//! Here's a few strategies: //! Here are a few strategies:
//! - Leverage the ability to return "None" and propogate None directly //! - Leverage the ability to return "None" and propagate None directly
//! - Instead of propogating "None" manually, use the "?" syntax sugar //! - Instead of propagating "None" manually, use the "?" syntax sugar
//! - Covert Results into Options with .ok() //! - Convert Results into Options with .ok()
//! - Manually display a separate screen by matching on Options/Results //! - Manually display a separate screen by matching on Options/Results
//! //!
//! There *are* plans to add helpful screens for when apps completely panic in WASM. However, you should really try to //! There *are* plans to add helpful screens for when apps completely panic in Wasm. However, you should really try to
//! avoid panicking. //! avoid panicking.
use dioxus::prelude::*; use dioxus::prelude::*;
fn main() {} fn main() {}
@ -42,7 +42,7 @@ static App1: FC<()> = |(cx, props)| {
/// However, it _does_ make the component go blank, which might not be desirable. /// However, it _does_ make the component go blank, which might not be desirable.
/// ///
/// This type of error handling is good when you have "selectors" that produce Some/None based on some state that's /// This type of error handling is good when you have "selectors" that produce Some/None based on some state that's
/// already controlled for higher in the tree. IE displaying a "Username" in a component that should only be shown if /// already controlled higher in the tree. i.e. displaying a "Username" in a component that should only be shown if
/// a user is logged in. /// a user is logged in.
/// ///
/// Dioxus will throw an error in the console if the None-path is ever taken. /// Dioxus will throw an error in the console if the None-path is ever taken.
@ -59,8 +59,8 @@ static App3: FC<()> = |(cx, props)| match get_data() {
None => cx.render(rsx!( div { "Failed to load data :(" } )), None => cx.render(rsx!( div { "Failed to load data :(" } )),
}; };
/// For errors that return results, it's possible short-circuit the match-based error handling with `.ok()` which converts /// For errors that return results, it's possible to short-circuit the match-based error handling with `.ok()` which converts
/// a Result<T, V> into an Option<T> and lets you /// a Result<T, V> into an Option<T> and lets you abort rendering by early-returning `None`
static App4: FC<()> = |(cx, props)| { static App4: FC<()> = |(cx, props)| {
let data = get_data_err().ok()?; let data = get_data_err().ok()?;
cx.render(rsx!( div { "{data}" } )) cx.render(rsx!( div { "{data}" } ))
@ -68,7 +68,7 @@ static App4: FC<()> = |(cx, props)| {
/// This is great error handling since it displays a failure state... with context! /// This is great error handling since it displays a failure state... with context!
/// ///
/// Hopefully you never need to disply a screen like this. It's rather bad taste /// Hopefully you'll never need to display a screen like this. It's rather bad taste
static App5: FC<()> = |(cx, props)| match get_data_err() { static App5: FC<()> = |(cx, props)| match get_data_err() {
Ok(data) => cx.render(rsx!( div { "{data}" } )), Ok(data) => cx.render(rsx!( div { "{data}" } )),
Err(c) => cx.render(rsx!( div { "Failed to load data: {c}" } )), Err(c) => cx.render(rsx!( div { "Failed to load data: {c}" } )),

View file

@ -3,7 +3,7 @@
//! //!
//! This example shows how to use inline styles in Dioxus components. //! This example shows how to use inline styles in Dioxus components.
//! //!
//! Inline styles function very similar to regular attributes, just grouped together in "style". //! Inline styles function very similarly to regular attributes, just grouped together in "style".
//! //!
//! Inline styles in Dioxus are more performant than React since we're able to cache attributes and compare by pointers. //! Inline styles in Dioxus are more performant than React since we're able to cache attributes and compare by pointers.
//! However, it's still not as performant as cascaded styles. Use with care. //! However, it's still not as performant as cascaded styles. Use with care.
@ -26,7 +26,7 @@ pub static Example: FC<()> = |(cx, props)| {
}) })
}; };
// .... technically the rsx! macro is slightly broken at the moment and alows styles not wrapped in style {} // .... technically the rsx! macro is slightly broken at the moment and allows styles not wrapped in style {}
// I haven't noticed any name collisions yet, and am tentatively leaving this behavior in.. // I haven't noticed any name collisions yet, and am tentatively leaving this behavior in..
// Don't rely on it. // Don't rely on it.
static Example2: FC<()> = |(cx, props)| { static Example2: FC<()> = |(cx, props)| {

View file

@ -8,7 +8,7 @@
//! //!
//! This also makes it easy to write "pull"-style iterators that don't have a known size. //! This also makes it easy to write "pull"-style iterators that don't have a known size.
//! //!
//! However, when the size of an iterator needs to be know for display purposes, collecting is fine. //! However, when the size of an iterator needs to be known for display purposes, collecting is fine.
use dioxus::prelude::*; use dioxus::prelude::*;

View file

@ -11,7 +11,7 @@ pub static Example: FC<()> = |(cx, props)| {
cx.render(rsx! { cx.render(rsx! {
ButtonList {} ButtonList {}
NonUpdatingEvents {} NonUpdatingEvents {}
DisablePropogation {} DisablePropagation {}
}) })
}; };
@ -42,13 +42,13 @@ static NonUpdatingEvents: FC<()> = |(cx, props)| {
}) })
}; };
static DisablePropogation: FC<()> = |(cx, props)| { static DisablePropagation: FC<()> = |(cx, props)| {
rsx!(cx, rsx!(cx,
div { div {
onclick: move |_| log::info!("event propogated to the div!") onclick: move |_| log::info!("event propagated to the div!")
button { button {
onclick: move |evt| { onclick: move |evt| {
log::info!("Button will allow propogation"); log::info!("Button will allow propagation");
} }
} }
} }

View file

@ -1,10 +1,10 @@
//! Example: Spread pattern for Components //! Example: Spread pattern for Components
//! -------------------------------------- //! --------------------------------------
//! //!
//! Dioxus supports the "spread" pattern for manually building a components properties. This is useful when props //! Dioxus supports the "spread" pattern for manually building a component's properties. This is useful when props
//! are passed down from a parent, or it's more ergonomic to construct props from outside the rsx! macro. //! are passed down from a parent, or it's more ergonomic to construct props from outside the rsx! macro.
//! //!
//! To use the spread pattern, simply pass ".." followed by a Rust epxression. This pattern also supports overriding //! To use the spread pattern, simply pass ".." followed by a Rust expression. This pattern also supports overriding
//! values, using the manual props as the base and then modifying fields specified with non-spread attributes. //! values, using the manual props as the base and then modifying fields specified with non-spread attributes.
use dioxus::prelude::*; use dioxus::prelude::*;

View file

@ -2,7 +2,7 @@
//! ----------------- //! -----------------
//! This example demonstrates how the use_suspense hook can be used to load and render asynchronous data. Suspense enables //! This example demonstrates how the use_suspense hook can be used to load and render asynchronous data. Suspense enables
//! components to wait on futures to complete before rendering the result into VNodes. These VNodes are immediately //! components to wait on futures to complete before rendering the result into VNodes. These VNodes are immediately
//! available in a suspended" fashion and will automatically propogate to the UI when the future completes. //! available in a suspended" fashion and will automatically propagate to the UI when the future completes.
//! //!
//! Currently, suspense futures are non-restartable. In the future, we'll provide more granular control of how to start, //! Currently, suspense futures are non-restartable. In the future, we'll provide more granular control of how to start,
//! stop, and reset these futures. //! stop, and reset these futures.

View file

@ -153,7 +153,7 @@
//! ``` //! ```
//! use dioxus::prelude::*; //! use dioxus::prelude::*;
//! fn main() { //! fn main() {
//! diouxs::web::launch(Example); //! dioxus::web::launch(Example);
//! } //! }
//! //!
//! pub pub static Example: FC<()> = |(cx, props)|{ //! pub pub static Example: FC<()> = |(cx, props)|{