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.
### 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.
### 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.
### 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.
### 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.
@ -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.
### 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?
- 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 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.
- You want to support browsers where Wasm or asm.js are not supported.
## License

View file

@ -2,7 +2,7 @@
![dioxuslogo](./images/dioxuslogo_full.png)
**Dioxus** is a framework and ecosystem for building fast, scalable, and robust user interfaces with the Rust programming language. This guide will help you get up-and-running with Dioxus running on the Web, Desktop, Mobile, and more.
**Dioxus** is a framework and ecosystem for building fast, scalable, and robust user interfaces with the Rust programming language. This guide will help you get up-and-running with Dioxus running on the Web, Desktop, Mobile, and more.
```rust, ignore
// An example Dioxus app - closely resembles React
@ -24,7 +24,7 @@ The Dioxus API and patterns closely resemble React - if this guide is lacking in
### 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.
@ -88,7 +88,7 @@ Examples:
### 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

@ -49,7 +49,7 @@ enum DomEdit {
}
```
The Dioxus diffing mechanism operates as a [stack machine](https://en.wikipedia.org/wiki/Stack_machine) where the "push_root" method pushes a new "real" DOM node onto the stack and "append_child" and "replace_with" both remove nodes from the stack.
The Dioxus diffing mechanism operates as a [stack machine](https://en.wikipedia.org/wiki/Stack_machine) where the "push_root" method pushes a new "real" DOM node onto the stack and "append_child" and "replace_with" both remove nodes from the stack.
### An example
@ -60,7 +60,7 @@ For the sake of understanding, lets consider this example - a very simple UI dec
rsx!( h1 {"hello world"} )
```
To get things started, Dioxus must first navigate to the container of this h1 tag. To "navigate" here, the internal diffing algorithm generates the DomEdit `PushRoot` where the ID of the root is the container.
To get things started, Dioxus must first navigate to the container of this h1 tag. To "navigate" here, the internal diffing algorithm generates the DomEdit `PushRoot` where the ID of the root is the container.
When the renderer receives this instruction, it pushes the actual Node onto its own stack. The real renderer's stack will look like this:
@ -228,7 +228,7 @@ For example, the `div` element is (approximately!) defined as such:
```rust
struct div;
impl div {
/// Some glorious documentaiton about the class proeprty.
/// Some glorious documentation about the class property.
#[inline]
fn class<'a>(&self, cx: NodeFactory<'a>, val: Arguments) -> Attribute<'a> {
cx.attr("class", val, None, false)
@ -251,7 +251,7 @@ There are three opportunities for platform incompatibilities to break your progr
The best hooks will properly detect the target platform and still provide functionality, failing gracefully when a platform is not supported. We encourage - and provide - an indication to the user on what platforms a hook supports. For issues 1 and 2, these return a result as to not cause panics on unsupported platforms. When designing your hooks, we recommend propagating this error upwards into user facing code, making it obvious that this particular service is not supported.
This particular code _will panic_ due to the unwrap on downcast_ref. Try to avoid these types of patterns.
This particular code _will panic_ due to the unwrap on downcast_ref. Try to avoid these types of patterns.
```rust
let div_ref = use_node_ref(cx);

View file

@ -1,12 +1,12 @@
# 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?
### 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.
### No APIs necessary!
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".

View file

@ -2,7 +2,7 @@
In this chapter of the book, we'll cover some core topics on how Dioxus works and how to best leverage the features to build a beautiful, reactive app.
At a very high level, Dioxus is simply a Rust framework for _declaring_ user interfaces and _reacting_ to changes.
At a very high level, Dioxus is simply a Rust framework for _declaring_ user interfaces and _reacting_ to changes.
1) We declare what we want our user interface to look like given a state using Rust-based logic and control flow.
2) We declare how we want our state to change when the user triggers an event.
@ -12,7 +12,7 @@ At a very high level, Dioxus is simply a Rust framework for _declaring_ user int
Dioxus is a *declarative* framework. This means that instead of manually writing calls to "create element" and "set element background to red," we simply *declare* what we want the element to look like and let Dioxus handle the differences.
Let's pretend that we have a stoplight we need to control - it has a color state with red, yellow, and green as options.
Let's pretend that we have a stoplight we need to control - it has a color state with red, yellow, and green as options.
Using an imperative approach, we would have to manually declare each element and then handlers for advancing the stoplight.

View file

@ -6,7 +6,7 @@ Yew subscriptions are used to schedule update for components into the future. Th
fn Component(cx: Component<()>) -> DomTree {
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();
}
```

View file

@ -56,7 +56,7 @@ async fn ExampleLoader(cx: Context<()>) -> Vnode {
match name {
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

@ -1,6 +1,6 @@
# VNodes and Elements
At the heart of Dioxus is the concept of an "element" - a container that can have children, properties, event handlers, and other important attributes. Dioxus only knows how to render the `VNode` datastructure - an Enum variant of an Element, Text, Components, Fragments, and Anchors.
At the heart of Dioxus is the concept of an "element" - a container that can have children, properties, event handlers, and other important attributes. Dioxus only knows how to render the `VNode` data structure - an Enum variant of an Element, Text, Components, Fragments, and Anchors.
Because Dioxus is meant for the Web and uses WebView as a desktop and mobile renderer, almost all elements in Dioxus share properties with their HTML counterpart. When we declare our elements, we'll do so using HTML semantics:
@ -27,8 +27,8 @@ And produce the corresponding html structure:
<div>hello world</div>
```
Our structure declared above is made of two variants of the `VNode` datastructure:
- A VElement with a tagname of `div`
Our structure declared above is made of two variants of the `VNode` data structure:
- A VElement with a tag name of `div`
- A VText with contents of `"hello world"`
## All the VNode types
@ -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)
- 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:

View file

@ -18,7 +18,7 @@ let val = 10; // rust
const val = 10; // js
```
However, `const` in JS does not prohibit you from modify the value itself only disallowing assignment. In Rust, immutable **is immutable**. You _never_ have to work about accidentally mutating data; mutating immutable data in Rust requires deliberate advanced datastructures that you won't find in your typical frontend code.
However, `const` in JS does not prohibit you from modify the value itself only disallowing assignment. In Rust, immutable **is immutable**. You _never_ have to work about accidentally mutating data; mutating immutable data in Rust requires deliberate advanced data structures that you won't find in your typical frontend code.
## How do strings work?

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:
```rust
use diouxs::prelude::*;
use dioxus::prelude::*;
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.
```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.
@ -124,7 +124,7 @@ The closure `FC<()>` syntax is identical to the function syntax, but with lifeti
fn App<'a>(cx: Context<'a>, props: &'a ()) -> DomTree<'a> {
cx.render(rsx! {
div { "Hello, world!" }
})
})
}
```

View file

@ -2,14 +2,14 @@
## 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.
- 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`
- 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`
- 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`

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")]
|| html! { <div> {"Loading data from server..."} </div> },
// Renderered on the server
// Rendered on the server
#[cfg(not(target_arch = "wasm32"))]
|| html! { <div> {"Server Data Loaded!"} </div> },
)

View file

@ -1,6 +1,6 @@
# 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`

View file

@ -15,10 +15,10 @@
//! 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
//! 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
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.

View file

@ -1,7 +1,7 @@
//! 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
//! 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.
/// 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;
use baller::Baller;
@ -104,7 +104,7 @@ pub static Example: FC<()> = |(cx, props)| {
// Matching
// 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.
// 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 {
true => rsx!(cx, h1 {"Top 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.
//!
//! 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
//! 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.
//!
//! 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
//! 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:
- Web via WASM
- Web via Wasm
- Desktop via webview integration
- Server-rendering with custom ToString implementation
- 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.
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

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.
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
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 concurrent. Components should be able to pause rendering using a threading mechanism.
- 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> {
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
// TODO: use const generics instead of the 4 estimation
stack: smallvec::SmallVec<[(u16, &'a VNode<'a>); 4]>,

View file

@ -2,7 +2,7 @@
//! 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
//! 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.
use crate::innerlude::{Context, DomTree, LazyNodes, FC};
@ -108,7 +108,7 @@ pub trait Properties: Sized {
///
/// # Safety
/// 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;
}

View file

@ -132,7 +132,7 @@ impl<'src> Context<'src> {
/// fn Component(cx: Context<()>) -> VNode {
/// // Lazy assemble the VNode tree
/// let lazy_tree = html! {<div> "Hello World" </div>};
///
///
/// // Actually build the tree and allocate it
/// cx.render(lazy_tree)
/// }
@ -203,7 +203,7 @@ impl<'src> Context<'src> {
.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>> {
let getter = &self.scope.shared.get_shared_context;
let ty = TypeId::of::<T>();
@ -225,7 +225,7 @@ impl<'src> Context<'src> {
/// todo!();
/// rsx!(cx, div { "Subtree {id}"})
/// };
/// ```
/// ```
pub fn create_subtree(self) -> Option<u32> {
self.scope.new_subtree()
}
@ -298,9 +298,9 @@ impl<'src> Context<'src> {
}
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.
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:
//!
//! 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.
//!
//! ## 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.
//! 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
//! array. The expectation is that implemenetors will use the ID as an index into a Vec of real nodes, allowing for passive
//! 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 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.
//!
//! When new vnodes are created through `cx.render`, they won't know which real node they correspond to. During diffing,
@ -30,34 +30,34 @@
//! fragment to be replaced with when it is no longer empty. This is guaranteed by logic in the NodeFactory - it is
//! impossible to craft a fragment with 0 elements - they must always have at least a single placeholder element. Adding
//! "dummy" nodes _is_ inefficient, but it makes our diffing algorithm faster and the implementation is completely up to
//! the platform.
//! the platform.
//!
//! Other implementations either don't support fragments or use a "child + sibling" pattern to represent them. Our code is
//! vastly simpler and more performant when we can just create a placeholder element while the fragment has no children.
//!
//! ### 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
//! 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.
//! 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
//! 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
//! and contents, without the need for the "use_suspense" hook. In the interim, this is the quickest way to get suspense working.
//! 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.
//!
//! ## 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
//! 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
//! 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
//! 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.
@ -70,11 +70,11 @@
//!
//! ## 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
//! 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
//! 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.
///
/// 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.
///
/// 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() {
log::debug!("Deadling expired before we could finished!");
log::debug!("Deadline expired before we could finished!");
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.
@ -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.
//
// 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.
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)
@ -753,7 +753,7 @@ impl<'bump> DiffMachine<'bump> {
self.remove_nodes(old_middle);
} else if old_middle.is_empty() {
// 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 {
// insert at the beginning of the old list
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.
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
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
@ -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.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
// 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
@ -952,7 +952,7 @@ impl<'bump> DiffMachine<'bump> {
if old_index == u32::MAX as usize {
stack.create_node(new_node, MountType::Absorb);
} 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::Diff {
new: new_node,

View file

@ -111,7 +111,7 @@ impl<'bump> DiffStack<'bump> {
self.instructions.push(DiffInstruction::PopScope);
// 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 });
}
}

View file

@ -35,7 +35,7 @@ pub struct UserEvent {
/// 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
/// implement this form of scheduling internally, however Dioxus will perform its own scheduling as well.
///
@ -69,17 +69,17 @@ pub enum EventPriority {
High = 2,
/// "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.
///
/// React calls these "continuous" events (e.g. mouse move, mouse wheel, touch move, etc).
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.
///
/// 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.
Low = 0,
@ -504,7 +504,7 @@ pub mod on {
/// _ => {}
/// }
/// ```
///
///
pub key: String,
/// Get the key code as an enum Variant.
@ -524,7 +524,7 @@ pub mod on {
/// _ => {}
/// }
/// ```
///
///
pub key_code: KeyCode,
/// Indicate if the `alt` modifier key was pressed during this keyboard event

View file

@ -6,9 +6,9 @@ use crate::FC;
/// 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
/// that would slow down the diffing and initializion process.
/// that would slow down the diffing and initialization process.
///
///
pub struct HeuristicsEngine {

View file

@ -30,10 +30,10 @@ impl HookList {
/// 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
/// Therefore, resetting is cosudered unsafe
/// Therefore, resetting is considered unsafe
///
/// 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) {
self.idx.set(0);
}

View file

@ -1,6 +1,6 @@
//! 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:
//! - [`use_hook`]

View file

@ -41,7 +41,7 @@ impl<'a> Mutations<'a> {
self.edits.push(InsertBefore { n, root });
}
// Remove Nodesfrom the dom
// Remove Nodes from the dom
pub(crate) fn remove(&mut self, id: u64) {
self.edits.push(Remove { root: id });
}
@ -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.
#[derive(Debug, PartialEq)]
#[cfg_attr(
@ -164,7 +164,7 @@ pub enum DomEdit<'bump> {
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
ReplaceWith {
root: u64,

View file

@ -15,7 +15,7 @@ use std::{
/// 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 [`html`] macro
/// - the [`NodeFactory`] API
@ -110,7 +110,7 @@ pub enum VNode<'src> {
/// # Example
///
/// ```rust
/// let node = cx.render(rsx! ( Fragment {} )).unwrap();
/// let node = cx.render(rsx! ( Fragment {} )).unwrap();
/// if let VNode::Fragment(frag) = node {
/// let root = &frag.children[0];
/// assert_eq!(root, VNode::Anchor);
@ -159,7 +159,7 @@ pub struct VAnchor {
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 text: &'src str,
@ -589,7 +589,7 @@ impl<'a> NodeFactory<'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.
pub trait IntoVNode<'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.
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
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
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
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
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.
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.
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
- 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)
@ -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.
///
/// 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 heuristics: HeuristicsEngine,
@ -187,7 +187,7 @@ impl Scheduler {
let sender = sender.clone();
Rc::new(move |id| {
//
log::debug!("scheduling immedate! {:?}", id);
log::debug!("scheduling immediate! {:?}", id);
sender.unbounded_send(SchedulerMsg::Immediate(id)).unwrap()
})
},
@ -387,7 +387,7 @@ impl Scheduler {
});
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) {
ran_scopes.insert(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.
- 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
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.
@ -583,7 +583,7 @@ impl Scheduler {
} else {
// todo: should this be a hard error?
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."
);
}

View file

@ -17,7 +17,7 @@ use std::{
/// The actual contents of the hooks, though, will be allocated with the standard allocator. These should not allocate as frequently.
///
/// We expose the `Scope` type so downstream users can traverse the Dioxus VirtualDOM for whatever
/// usecase they might have.
/// use case they might have.
pub struct Scope {
// Book-keeping about our spot in the arena
pub(crate) parent_idx: Option<ScopeId>,
@ -231,20 +231,20 @@ impl Scope {
}
/// 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
/// 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.
///
/// 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.
///
/// This also makes sure that drop order is consistent and predictable. All resources that rely on being dropped will
/// be dropped.
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
// run the hooks (which hold an &mut Referrence)
// run the hooks (which hold an &mut Reference)
// right now, we don't drop
self.borrowed_props
.get_mut()

View file

@ -3,7 +3,7 @@
//! This module provides the primary mechanics to create a hook-based, concurrent VDOM for Rust.
//!
//! In this file, multiple items are defined. This file is big, but should be documented well to
//! navigate the innerworkings of the Dom. We try to keep these main mechanics in this file to limit
//! navigate the inner workings of the Dom. We try to keep these main mechanics in this file to limit
//! the possible exposed API surface (keep fields private). This particular implementation of VDOM
//! is extremely efficient, but relies on some unsafety under the hood to do things like manage
//! micro-heaps for components. We are currently working on refactoring the safety out into safe(r)
@ -11,10 +11,10 @@
//!
//! Included is:
//! - 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 [`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.
//! 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.
///
/// 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>(
root: FC<P>,
root_props: P,
@ -173,7 +173,7 @@ impl VirtualDom {
/// 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.
pub fn base_scope(&self) -> &Scope {
self.scheduler.pool.get_scope(self.base_scope).unwrap()
@ -186,7 +186,7 @@ impl 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.
///
/// ## Example
@ -258,7 +258,7 @@ impl VirtualDom {
/// 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
/// 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
//! 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
//! rather than building new harder-to-misuse patterns.
//!
//! In this list we showcase:
//! - Not adding keys for iterators
//! - Heavily nested fragments
//! - Understadning ordering of set_state
//! - Understanding ordering of set_state
//! - Naming conventions
//! - 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
/// 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:
/// - Unique
/// - 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
/// 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
/// mutative normalization while Dioxus keeps your VNodes immutable. This means that deepely nested fragments make Dioxus
/// perform unnecessary work. Prefer one or two levels of fragments / nested components until presenting a true dom element.
/// 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
/// 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.
///
/// 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.
@ -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
@ -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
/// 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, props)| {
static AntipatternRelyingOnSetState: 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"
@ -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
/// critical than other potential misues. In short:
/// critical than other potential misuses. In short:
/// - Only raw elements may start with a lowercase 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!();
/// Antipattern: Misusing hooks
/// ---------------------------
///
/// This pattern is an unfortunate one where Dioxus supports the same behavior as in other frameworks. Dioxus supports
/// "hooks" - IE "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
/// This pattern is an unfortunate one where Dioxus replicates the same behavior as other frameworks. Dioxus supports
/// "hooks" - i.e. "memory cells" that allow a value to be stored between renders. This allows other hooks to tap into
/// 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.
///
/// This means that hooks may not be misued:
/// This means that hooks may not be misused:
/// - Called out of order
/// - Called in a conditional
/// - 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
/// 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)]
struct MisuedHooksProps {
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
/// Dioxus's virtual element types as well as their true native counterparts. Downcasting to Dioxus' virtual elements
/// Occasionally it's useful to get the ref of an element to handle it directly. Elements support downcasting to
/// 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
/// 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.
// 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
/// let div_ref = use_node_ref(&cx);

View file

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

View file

@ -1,14 +1,14 @@
//! Example: Children
//! -----------------
//!
//! Dioxus supports passing children in from the parent. These children are allocated in the parent and just forced
//! into the child. Components that pass in children may not be safely memoized, though in practice its rare for a
//! 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 it's rare for a
//! 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
//! 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
//! 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
//! 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.
//!
//! 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.
//!
//! 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.
use dioxus::prelude::*;
@ -58,7 +58,7 @@ pub static Example1: FC<MyProps1> = |(cx, props)| {
// or with optional chaining
{
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!"}))
}
}

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
//! 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.
//!
//! So, obviously, you need to handle your errors.
//!
//! Fortunately, it's easy to avoid panics, even during quick prototyping.
//!
//! Here's a few strategies:
//! - Leverage the ability to return "None" and propogate None directly
//! - Instead of propogating "None" manually, use the "?" syntax sugar
//! - Covert Results into Options with .ok()
//! Here are a few strategies:
//! - Leverage the ability to return "None" and propagate None directly
//! - Instead of propagating "None" manually, use the "?" syntax sugar
//! - Convert Results into Options with .ok()
//! - 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.
use dioxus::prelude::*;
fn main() {}
@ -42,7 +42,7 @@ static App1: FC<()> = |(cx, props)| {
/// 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
/// 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.
///
/// 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 :(" } )),
};
/// 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
/// 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 abort rendering by early-returning `None`
static App4: FC<()> = |(cx, props)| {
let data = get_data_err().ok()?;
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!
///
/// 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() {
Ok(data) => cx.render(rsx!( div { "{data}" } )),
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.
//!
//! 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.
//! 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..
// Don't rely on it.
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.
//!
//! 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::*;

View file

@ -11,7 +11,7 @@ pub static Example: FC<()> = |(cx, props)| {
cx.render(rsx! {
ButtonList {}
NonUpdatingEvents {}
DisablePropogation {}
DisablePropagation {}
})
};
@ -42,13 +42,13 @@ static NonUpdatingEvents: FC<()> = |(cx, props)| {
})
};
static DisablePropogation: FC<()> = |(cx, props)| {
static DisablePropagation: FC<()> = |(cx, props)| {
rsx!(cx,
div {
onclick: move |_| log::info!("event propogated to the div!")
onclick: move |_| log::info!("event propagated to the div!")
button {
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
//! --------------------------------------
//!
//! 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.
//!
//! 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.
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
//! 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,
//! stop, and reset these futures.

View file

@ -109,7 +109,7 @@
//! cx.use_hook(
//! // Initializer stores a value
//! |hook_idx| String::new("stored_data"),
//!
//!
//! // Runner returns the hook value every time the component is rendered
//! |hook| &*hook,
//!
@ -153,7 +153,7 @@
//! ```
//! use dioxus::prelude::*;
//! fn main() {
//! diouxs::web::launch(Example);
//! dioxus::web::launch(Example);
//! }
//!
//! pub pub static Example: FC<()> = |(cx, props)|{