Subtree memorization / reactive templates (#488)
This commit adds subtree memoization to Dioxus. Subtree memoization is basically a compile-time step that drastically reduces the amount of work the diffing engine needs to do at runtime by extracting non-changing nodes out into a static "template." Templates are then understood by the various renderers in the ecosystem as a faster way of rendering the same items. For example, in the web, templates are simply a set of DOM Nodes created once and then cloned later. This is the same pattern frameworks like Lithtml and SolidJS use to achieve near-perfect performance. Subtree memoization adds an additional level of complexity to Dioxus. The RSX macro needs to be much smarter to identify changing/nonchanging nodes and generate a mapping between the Template and its runtime counterparts. This commit represents a working starter point for this work, adding support for templates for the web, desktop, liveview, ssr, and native-core renderers. In the future we will try to shrink code generation, generally improve performance, and simplify our implementation.
This commit is contained in:
1 parent
b32fd2d2cd
commit
047ed1e553
80 files changed
+6774
-2552
No files matched your search
+18
-11
@@ -1,6 +1,6 @@
|
||||
use crate::{node::PreventDefault, Dom};
|
||||
|
||||
use dioxus_core::ElementId;
|
||||
use dioxus_core::GlobalNodeId;
|
||||
use dioxus_native_core::utils::{ElementProduced, PersistantElementIter};
|
||||
use dioxus_native_core_macro::sorted_str_slice;
|
||||
|
||||
@@ -69,7 +69,10 @@ impl NodeDepState<()> for Focus {
|
||||
|
||||
fn reduce(&mut self, node: NodeView<'_>, _sibling: (), _: &Self::Ctx) -> bool {
|
||||
let new = Focus {
|
||||
level: if let Some(a) = node.attributes().find(|a| a.name == "tabindex") {
|
||||
level: if let Some(a) = node
|
||||
.attributes()
|
||||
.and_then(|mut a| a.find(|a| a.attribute.name == "tabindex"))
|
||||
{
|
||||
if let Some(index) = a
|
||||
.value
|
||||
.as_int32()
|
||||
@@ -87,8 +90,12 @@ impl NodeDepState<()> for Focus {
|
||||
}
|
||||
} else if node
|
||||
.listeners()
|
||||
.iter()
|
||||
.any(|l| FOCUS_EVENTS.binary_search(&l.event).is_ok())
|
||||
.map(|mut listeners| {
|
||||
listeners
|
||||
.any(|l| FOCUS_EVENTS.binary_search(&l).is_ok())
|
||||
.then(|| ())
|
||||
})
|
||||
.is_some()
|
||||
{
|
||||
FocusLevel::Focusable
|
||||
} else {
|
||||
@@ -110,7 +117,7 @@ const FOCUS_ATTRIBUTES: &[&str] = &sorted_str_slice!(["tabindex"]);
|
||||
#[derive(Default)]
|
||||
pub(crate) struct FocusState {
|
||||
pub(crate) focus_iter: PersistantElementIter,
|
||||
pub(crate) last_focused_id: Option<ElementId>,
|
||||
pub(crate) last_focused_id: Option<GlobalNodeId>,
|
||||
pub(crate) focus_level: FocusLevel,
|
||||
pub(crate) dirty: bool,
|
||||
}
|
||||
@@ -224,9 +231,9 @@ impl FocusState {
|
||||
|
||||
pub(crate) fn prune(&mut self, mutations: &dioxus_core::Mutations, rdom: &Dom) {
|
||||
fn remove_children(
|
||||
to_prune: &mut [&mut Option<ElementId>],
|
||||
to_prune: &mut [&mut Option<GlobalNodeId>],
|
||||
rdom: &Dom,
|
||||
removed: ElementId,
|
||||
removed: GlobalNodeId,
|
||||
) {
|
||||
for opt in to_prune.iter_mut() {
|
||||
if let Some(id) = opt {
|
||||
@@ -235,7 +242,7 @@ impl FocusState {
|
||||
}
|
||||
}
|
||||
}
|
||||
if let NodeType::Element { children, .. } = &rdom[removed].node_type {
|
||||
if let NodeType::Element { children, .. } = &rdom[removed].node_data.node_type {
|
||||
for child in children {
|
||||
remove_children(to_prune, rdom, *child);
|
||||
}
|
||||
@@ -249,19 +256,19 @@ impl FocusState {
|
||||
dioxus_core::DomEdit::ReplaceWith { root, .. } => remove_children(
|
||||
&mut [&mut self.last_focused_id],
|
||||
rdom,
|
||||
ElementId(*root as usize),
|
||||
rdom.decode_id(*root),
|
||||
),
|
||||
dioxus_core::DomEdit::Remove { root } => remove_children(
|
||||
&mut [&mut self.last_focused_id],
|
||||
rdom,
|
||||
ElementId(*root as usize),
|
||||
rdom.decode_id(*root),
|
||||
),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn set_focus(&mut self, rdom: &mut Dom, id: ElementId) {
|
||||
pub(crate) fn set_focus(&mut self, rdom: &mut Dom, id: GlobalNodeId) {
|
||||
if let Some(old) = self.last_focused_id.replace(id) {
|
||||
rdom[old].state.focused = false;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user