Significant perf improvements

This commit is contained in:
Greg Johnston 2022-08-29 08:04:59 -04:00
parent d1b5e652c1
commit d6c007dcc4
3 changed files with 64 additions and 15 deletions

View file

@ -1,12 +1,38 @@
use std::rc::Rc;
use leptos_reactive::Scope;
#[derive(Clone)]
pub enum Attribute {
String(String),
Fn(Box<dyn Fn() -> Attribute>),
Fn(Rc<dyn Fn() -> Attribute>),
Option(Option<String>),
Bool(bool),
}
impl PartialEq for Attribute {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::String(l0), Self::String(r0)) => l0 == r0,
(Self::Fn(_), Self::Fn(_)) => false,
(Self::Option(l0), Self::Option(r0)) => l0 == r0,
(Self::Bool(l0), Self::Bool(r0)) => l0 == r0,
_ => false,
}
}
}
impl std::fmt::Debug for Attribute {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::String(arg0) => f.debug_tuple("String").field(arg0).finish(),
Self::Fn(_) => f.debug_tuple("Fn").finish(),
Self::Option(arg0) => f.debug_tuple("Option").field(arg0).finish(),
Self::Bool(arg0) => f.debug_tuple("Bool").field(arg0).finish(),
}
}
}
pub trait IntoAttribute {
fn into_attribute(self, cx: Scope) -> Attribute;
}
@ -35,7 +61,7 @@ where
U: IntoAttribute,
{
fn into_attribute(self, cx: Scope) -> Attribute {
let modified_fn = Box::new(move || (self)().into_attribute(cx));
let modified_fn = Rc::new(move || (self)().into_attribute(cx));
Attribute::Fn(modified_fn)
}
}

View file

@ -37,6 +37,7 @@ macro_rules! prop_type {
};
}
prop_type!(JsValue);
prop_type!(String);
prop_type!(&String);
prop_type!(&str);

View file

@ -40,7 +40,13 @@ pub fn attribute(cx: Scope, el: &web_sys::Element, attr_name: &'static str, valu
match value {
Attribute::Fn(f) => {
let el = el.clone();
create_render_effect(cx, move |_| attribute_expression(&el, attr_name, f()));
create_render_effect(cx, move |old| {
let new = f();
if old.as_ref() != Some(&new) {
attribute_expression(&el, attr_name, new.clone());
}
new
});
}
_ => attribute_expression(el, attr_name, value),
}
@ -62,7 +68,13 @@ pub fn property(cx: Scope, el: &web_sys::Element, prop_name: &'static str, value
match value {
Property::Fn(f) => {
let el = el.clone();
create_render_effect(cx, move |_| property_expression(&el, prop_name, f()));
create_render_effect(cx, move |old| {
let new = f();
if old.as_ref() != Some(&new) && !(old == None && new == JsValue::UNDEFINED) {
property_expression(&el, prop_name, new.clone())
}
new
});
}
Property::Value(value) => property_expression(el, prop_name, value),
}
@ -76,7 +88,13 @@ pub fn class(cx: Scope, el: &web_sys::Element, class_name: &'static str, value:
match value {
Class::Fn(f) => {
let el = el.clone();
create_render_effect(cx, move |_| class_expression(&el, class_name, f()));
create_render_effect(cx, move |old| {
let new = f();
if old.as_ref() != Some(&new) && (old.is_some() || new) {
class_expression(&el, class_name, new)
}
new
});
}
Class::Value(value) => class_expression(el, class_name, value),
}
@ -106,16 +124,21 @@ pub fn insert(
.unwrap_or(Child::Null);
let mut value = f();
while let Child::Fn(f) = value {
value = f();
}
Some(insert_expression(
parent.clone().unchecked_into(),
&value,
current,
&before,
))
if current != value {
while let Child::Fn(f) = value {
value = f();
}
Some(insert_expression(
parent.clone().unchecked_into(),
&value,
current,
&before,
))
} else {
Some(current)
}
});
}
_ => {
@ -157,7 +180,6 @@ pub fn insert_expression(
// if the new value is null, clean children out of the parent up to the marker node
Child::Null => {
if let Child::Node(old_node) = current {
crate::debug_warn!("just remove the node");
remove_child(&parent, &old_node);
Child::Null
} else {