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
@@ -1,6 +1,6 @@
|
||||
#![allow(unused, non_upper_case_globals, non_snake_case)]
|
||||
|
||||
use dioxus::prelude::*;
|
||||
use dioxus::{core_macro::rsx_without_templates, prelude::*};
|
||||
use dioxus_core::{DomEdit, Mutations, SchedulerMsg, ScopeId};
|
||||
use std::rc::Rc;
|
||||
use DomEdit::*;
|
||||
@@ -11,12 +11,12 @@ fn shared_state_test() {
|
||||
|
||||
static App: Component = |cx| {
|
||||
cx.provide_context(Rc::new(MySharedState("world!")));
|
||||
cx.render(rsx!(Child {}))
|
||||
cx.render(rsx_without_templates!(Child {}))
|
||||
};
|
||||
|
||||
static Child: Component = |cx| {
|
||||
let shared = cx.consume_context::<Rc<MySharedState>>()?;
|
||||
cx.render(rsx!("Hello, {shared.0}"))
|
||||
cx.render(rsx_without_templates!("Hello, {shared.0}"))
|
||||
};
|
||||
|
||||
let mut dom = VirtualDom::new(App);
|
||||
@@ -42,13 +42,13 @@ fn swap_test() {
|
||||
cx.provide_context(Rc::new(MySharedState("world!")));
|
||||
|
||||
let child = match *val % 2 {
|
||||
0 => rsx!(
|
||||
0 => rsx_without_templates!(
|
||||
Child1 {
|
||||
Child1 { }
|
||||
Child2 { }
|
||||
}
|
||||
),
|
||||
_ => rsx!(
|
||||
_ => rsx_without_templates!(
|
||||
Child2 {
|
||||
Child2 { }
|
||||
Child2 { }
|
||||
@@ -56,7 +56,7 @@ fn swap_test() {
|
||||
),
|
||||
};
|
||||
|
||||
cx.render(rsx!(
|
||||
cx.render(rsx_without_templates!(
|
||||
Router {
|
||||
div { child }
|
||||
}
|
||||
@@ -65,14 +65,14 @@ fn swap_test() {
|
||||
|
||||
#[inline_props]
|
||||
fn Router<'a>(cx: Scope, children: Element<'a>) -> Element<'a> {
|
||||
cx.render(rsx!(div { children }))
|
||||
cx.render(rsx_without_templates!(div { children }))
|
||||
}
|
||||
|
||||
#[inline_props]
|
||||
fn Child1<'a>(cx: Scope, children: Element<'a>) -> Element {
|
||||
let shared = cx.consume_context::<Rc<MySharedState>>().unwrap();
|
||||
println!("Child1: {}", shared.0);
|
||||
cx.render(rsx! {
|
||||
cx.render(rsx_without_templates! {
|
||||
div {
|
||||
"{shared.0}",
|
||||
children
|
||||
@@ -84,7 +84,7 @@ fn swap_test() {
|
||||
fn Child2<'a>(cx: Scope, children: Element<'a>) -> Element {
|
||||
let shared = cx.consume_context::<Rc<MySharedState>>().unwrap();
|
||||
println!("Child2: {}", shared.0);
|
||||
cx.render(rsx! {
|
||||
cx.render(rsx_without_templates! {
|
||||
h1 {
|
||||
"{shared.0}",
|
||||
children
|
||||
|
||||
Reference in new issue
Block a user