This commit is contained in:
Evan Almloff 2022-05-27 18:26:31 -05:00
commit 4b1ea5879d
11 changed files with 28 additions and 29 deletions

View file

@ -1,26 +1,26 @@
#![warn(clippy::pedantic)] #![warn(clippy::pedantic)]
#![allow(clippy::cast_possible_truncation)] #![allow(clippy::cast_possible_truncation)]
//! This module contains the stateful [`DiffState`] and all methods to diff [`VNodes`], their properties, and their children. //! This module contains the stateful [`DiffState`] and all methods to diff [`VNode`]s, their properties, and their children.
//! //!
//! The [`DiffState`] calculates the diffs between the old and new frames, updates the new nodes, and generates a set //! The [`DiffState`] calculates the diffs between the old and new frames, updates the new nodes, and generates a set
//! of mutations for the [`RealDom`] to apply. //! of mutations for the renderer to apply.
//! //!
//! ## 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, cancellation, [`NodeRefs`], pausing, priority //! Components, Fragments, Suspense, `SubTree` memoization, incremental diffing, cancellation, pausing, priority
//! scheduling, and additional batching operations. //! scheduling, and additional batching operations.
//! //!
//! ## Implementation Details: //! ## Implementation Details:
//! //!
//! ### IDs for elements //! ### IDs for elements
//! -------------------- //! --------------------
//! 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.
//! 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 indices 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 implementors 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 [`crate::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,
//! we always make sure to copy over the ID. If we don't do this properly, the [`ElementId`] will be populated incorrectly //! we always make sure to copy over the ID. If we don't do this properly, the [`ElementId`] will be populated incorrectly
@ -30,7 +30,7 @@
//! -------------------- //! --------------------
//! Fragments (nodes without a parent) are supported through a combination of "replace with" and anchor vnodes. Fragments //! Fragments (nodes without a parent) are supported through a combination of "replace with" and anchor vnodes. Fragments
//! can be particularly challenging when they are empty, so the anchor node lets us "reserve" a spot for the empty //! can be particularly challenging when they are empty, so the anchor node lets us "reserve" a spot for the empty
//! fragment to be replaced with when it is no longer empty. This is guaranteed by logic in the [`NodeFactory`] - it is //! fragment to be replaced with when it is no longer empty. This is guaranteed by logic in the [`crate::innerlude::NodeFactory`] - it is
//! impossible to craft a fragment with 0 elements - they must always have at least a single placeholder element. Adding //! 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 //! "dummy" nodes _is_ inefficient, but it makes our diffing algorithm faster and the implementation is completely up to
//! the platform. //! the platform.
@ -44,13 +44,13 @@
//! 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 [`crate::virtual_dom::VirtualDom::work_with_deadline`] 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 with 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 a `use_suspense` hook. In the interim, this is the quickest way to get Suspense working.
//! //!
//! ## Subtree Memoization //! ## Subtree Memoization
//! ----------------------- //! -----------------------

View file

@ -150,7 +150,7 @@ impl AnyEvent {
/// You should prefer to use the name of the event directly, rather than /// You should prefer to use the name of the event directly, rather than
/// the UiEvent<T> generic type. /// the UiEvent<T> generic type.
/// ///
/// For the HTML crate, this would include [`MouseEvent`], [`FormEvent`] etc. /// For the HTML crate, this would include MouseEvent, FormEvent etc.
pub struct UiEvent<T> { pub struct UiEvent<T> {
/// The internal data of the event /// The internal data of the event
/// This is wrapped in an Arc so that it can be sent across threads /// This is wrapped in an Arc so that it can be sent across threads

View file

@ -550,7 +550,7 @@ impl<'a> NodeFactory<'a> {
})) }))
} }
/// Create a new [`VNode::VElement`] /// Create a new [`VNode::Element`]
pub fn element( pub fn element(
&self, &self,
el: impl DioxusElement, el: impl DioxusElement,
@ -569,7 +569,7 @@ impl<'a> NodeFactory<'a> {
) )
} }
/// Create a new [`VNode::VElement`] without the trait bound /// Create a new [`VNode::Element`] without the trait bound
/// ///
/// IE pass in "div" instead of `div` /// IE pass in "div" instead of `div`
pub fn raw_element( pub fn raw_element(
@ -637,7 +637,7 @@ impl<'a> NodeFactory<'a> {
} }
} }
/// Create a new [`VNode::VComponent`] /// Create a new [`VNode::Component`]
pub fn component<P>( pub fn component<P>(
&self, &self,
component: fn(Scope<'a, P>) -> Element, component: fn(Scope<'a, P>) -> Element,
@ -684,7 +684,7 @@ impl<'a> NodeFactory<'a> {
} }
} }
/// Create a new [`VNode::VFragment`] from a root of the rsx! call /// Create a new [`VNode::Fragment`] from a root of the rsx! call
pub fn fragment_root<'b, 'c>( pub fn fragment_root<'b, 'c>(
self, self,
node_iter: impl IntoIterator<Item = impl IntoVNode<'a> + 'c> + 'b, node_iter: impl IntoIterator<Item = impl IntoVNode<'a> + 'c> + 'b,
@ -705,7 +705,7 @@ impl<'a> NodeFactory<'a> {
} }
} }
/// Create a new [`VNode::VFragment`] from any iterator /// Create a new [`VNode::Fragment`] from any iterator
pub fn fragment_from_iter<'b, 'c>( pub fn fragment_from_iter<'b, 'c>(
self, self,
node_iter: impl IntoIterator<Item = impl IntoVNode<'a> + 'c> + 'b, node_iter: impl IntoIterator<Item = impl IntoVNode<'a> + 'c> + 'b,

View file

@ -1,7 +1,7 @@
use crate::innerlude::*; use crate::innerlude::*;
/// An iterator that only yields "real" [`Element`]s. IE only Elements that are /// An iterator that only yields "real" [`Element`]s. IE only Elements that are
/// not [`VNode::VComponent`] or [`VNode::VFragment`], . /// not [`VNode::Component`] or [`VNode::Fragment`], .
pub struct ElementIdIterator<'a> { pub struct ElementIdIterator<'a> {
vdom: &'a VirtualDom, vdom: &'a VirtualDom,

View file

@ -447,7 +447,7 @@ pub mod on {
/// Get the key code as an enum Variant. /// Get the key code as an enum Variant.
/// ///
/// This is intended for things like arrow keys, escape keys, function keys, and other non-international keys. /// This is intended for things like arrow keys, escape keys, function keys, and other non-international keys.
/// To match on unicode sequences, use the [`KeyboardEvent::key`] method - this will return a string identifier instead of a limited enum. /// To match on unicode sequences, use the [`KeyboardData::key`] method - this will return a string identifier instead of a limited enum.
/// ///
/// ///
/// ## Example /// ## Example

View file

@ -15,7 +15,7 @@ use crate::{
/// A Dom that can sync with the VirtualDom mutations intended for use in lazy renderers. /// A Dom that can sync with the VirtualDom mutations intended for use in lazy renderers.
/// The render state passes from parent to children and or accumulates state from children to parents. /// The render state passes from parent to children and or accumulates state from children to parents.
/// To get started implement [PushedDownState] and or [BubbledUpState] and call [RealDom::apply_mutations] to update the dom and [RealDom::update_state] to update the state of the nodes. /// To get started implement [crate::state::ParentDepState], [crate::state::NodeDepState], or [crate::state::ChildDepState] and call [RealDom::apply_mutations] to update the dom and [RealDom::update_state] to update the state of the nodes.
#[derive(Debug)] #[derive(Debug)]
pub struct RealDom<S: State> { pub struct RealDom<S: State> {
root: usize, root: usize,
@ -712,7 +712,7 @@ impl<S: State> IndexMut<ElementId> for RealDom<S> {
} }
} }
/// The node is stored client side and stores only basic data about the node. For more complete information about the node see [`domNode::element`]. /// The node is stored client side and stores only basic data about the node.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Node<S: State> { pub struct Node<S: State> {
/// The id of the node this node was created from. /// The id of the node this node was created from.

View file

@ -44,10 +44,10 @@ pub(crate) fn union_ordered_iter<T: Ord + Debug>(
} }
/// This state is derived from children. For example a node's size could be derived from the size of children. /// This state is derived from children. For example a node's size could be derived from the size of children.
/// Called when the current node's node properties are modified, a child's [BubbledUpState] is modified or a child is removed. /// Called when the current node's node properties are modified, a child's [ChildDepState] is modified or a child is removed.
/// Called at most once per update. /// Called at most once per update.
pub trait ChildDepState { pub trait ChildDepState {
/// The context is passed to the [PushedDownState::reduce] when it is pushed down. /// The context is passed to the [ChildDepState::reduce] when it is pushed down.
/// This is sometimes nessisary for lifetime purposes. /// This is sometimes nessisary for lifetime purposes.
type Ctx; type Ctx;
/// This must be either a [ChildDepState] or [NodeDepState] /// This must be either a [ChildDepState] or [NodeDepState]
@ -64,10 +64,10 @@ pub trait ChildDepState {
} }
/// This state that is passed down to children. For example text properties (`<b>` `<i>` `<u>`) would be passed to children. /// This state that is passed down to children. For example text properties (`<b>` `<i>` `<u>`) would be passed to children.
/// Called when the current node's node properties are modified or a parrent's [PushedDownState] is modified. /// Called when the current node's node properties are modified or a parrent's [ParentDepState] is modified.
/// Called at most once per update. /// Called at most once per update.
pub trait ParentDepState { pub trait ParentDepState {
/// The context is passed to the [PushedDownState::reduce] when it is pushed down. /// The context is passed to the [ParentDepState::reduce] when it is pushed down.
/// This is sometimes nessisary for lifetime purposes. /// This is sometimes nessisary for lifetime purposes.
type Ctx; type Ctx;
/// This must be either a [ParentDepState] or [NodeDepState] /// This must be either a [ParentDepState] or [NodeDepState]
@ -77,7 +77,7 @@ pub trait ParentDepState {
} }
/// This state that is upadated lazily. For example any propertys that do not effect other parts of the dom like bg-color. /// This state that is upadated lazily. For example any propertys that do not effect other parts of the dom like bg-color.
/// Called when the current node's node properties are modified or a parrent's [PushedDownState] is modified. /// Called when the current node's node properties are modified or a sibling's [NodeDepState] is modified.
/// Called at most once per update. /// Called at most once per update.
pub trait NodeDepState { pub trait NodeDepState {
type Ctx; type Ctx;

View file

@ -43,9 +43,9 @@
<span> | </span> <span> | </span>
<a href="https://github.com/DioxusLabs/example-projects"> Examples </a> <a href="https://github.com/DioxusLabs/example-projects"> Examples </a>
<span> | </span> <span> | </span>
<a href="https://dioxuslabs.com/guide"> Guide (0.1.8) </a> <a href="https://dioxuslabs.com/router"> Guide (Latest) </a>
<span> | </span> <span> | </span>
<a href="https://dioxuslabs.com/nightly/guide"> Guide (Master) </a> <a href="https://dioxuslabs.com/nightly/router"> Guide (Master) </a>
</h3> </h3>
</div> </div>

View file

@ -1,7 +1,6 @@
//! Parse components into the VComponent VNode //! Parse components into the VNode::Component variant
//! ========================================== //! ==========================================
//! //!
//! This parsing path emerges from [`AmbiguousElement`] which supports validation of the vcomponent format.
//! We can be reasonably sure that whatever enters this parsing path is in the right format. //! We can be reasonably sure that whatever enters this parsing path is in the right format.
//! This feature must support //! This feature must support
//! - [x] Namespaced components //! - [x] Namespaced components

View file

@ -11,7 +11,7 @@ documentation = "https://dioxuslabs.com"
keywords = ["dom", "ui", "gui", "react", "wasm"] keywords = ["dom", "ui", "gui", "react", "wasm"]
[dependencies] [dependencies]
dioxus-core = { path = "../core", version = "^0.2.1" } dioxus-core = { path = "../core", version = "^0.2.1", features = ["serialize"] }
dioxus-html = { path = "../html", version = "^0.2.1", features = ["wasm-bind"] } dioxus-html = { path = "../html", version = "^0.2.1", features = ["wasm-bind"] }
dioxus-interpreter-js = { path = "../interpreter", version = "^0.2.1", features = [ dioxus-interpreter-js = { path = "../interpreter", version = "^0.2.1", features = [
"web" "web"

View file

@ -26,7 +26,7 @@
// main thread. // main thread.
// //
// React solves this problem by breaking up the rendering process into a "diff" phase and a "render" phase. In Dioxus, // React solves this problem by breaking up the rendering process into a "diff" phase and a "render" phase. In Dioxus,
// the diff phase is non-blocking, using "yield_now" to allow the browser to process other events. When the diff phase // the diff phase is non-blocking, using "work_with_deadline" to allow the browser to process other events. When the diff phase
// is finally complete, the VirtualDOM will return a set of "Mutations" for this crate to apply. // is finally complete, the VirtualDOM will return a set of "Mutations" for this crate to apply.
// //
// Here, we schedule the "diff" phase during the browser's idle period, achieved by calling RequestIdleCallback and then // Here, we schedule the "diff" phase during the browser's idle period, achieved by calling RequestIdleCallback and then