mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-27 06:30:20 +00:00
Merge https://github.com/DioxusLabs/dioxus into jk/rsx-refactor
This commit is contained in:
commit
4b1ea5879d
11 changed files with 28 additions and 29 deletions
|
@ -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
|
||||||
//! -----------------------
|
//! -----------------------
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue