From 28a3859365bfa192e5ccd0750481588f830b20aa Mon Sep 17 00:00:00 2001 From: Greg Johnston Date: Mon, 16 Dec 2024 19:23:15 -0500 Subject: [PATCH] fix: rebuilding of `InertElement` (closes #3368) (#3370) --- tachys/src/html/mod.rs | 42 ++++++++++++++++++++++++++++++++------ tachys/src/renderer/dom.rs | 3 ++- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/tachys/src/html/mod.rs b/tachys/src/html/mod.rs index c4225be702..67af1a5bd3 100644 --- a/tachys/src/html/mod.rs +++ b/tachys/src/html/mod.rs @@ -2,8 +2,11 @@ use self::attribute::Attribute; use crate::{ hydration::Cursor, no_attrs, - prelude::AddAnyAttr, - renderer::{CastFrom, Rndr}, + prelude::{AddAnyAttr, Mountable}, + renderer::{ + dom::{Element, Node}, + CastFrom, Rndr, + }, view::{Position, PositionState, Render, RenderHtml}, }; use std::borrow::Cow; @@ -90,14 +93,41 @@ impl InertElement { } } +/// Retained view state for [`InertElement`]. +pub struct InertElementState(Cow<'static, str>, Element); + +impl Mountable for InertElementState { + fn unmount(&mut self) { + self.1.unmount(); + } + + fn mount(&mut self, parent: &Element, marker: Option<&Node>) { + self.1.mount(parent, marker) + } + + fn insert_before_this(&self, child: &mut dyn Mountable) -> bool { + self.1.insert_before_this(child) + } +} + impl Render for InertElement { - type State = crate::renderer::types::Element; + type State = InertElementState; fn build(self) -> Self::State { - Rndr::create_element_from_html(&self.html) + let el = Rndr::create_element_from_html(&self.html); + InertElementState(self.html, el) } - fn rebuild(self, _state: &mut Self::State) {} + fn rebuild(self, state: &mut Self::State) { + let InertElementState(prev, el) = state; + if &self.html != prev { + let mut new_el = Rndr::create_element_from_html(&self.html); + el.insert_before_this(&mut new_el); + el.unmount(); + *el = new_el; + *prev = self.html; + } + } } impl AddAnyAttr for InertElement { @@ -157,6 +187,6 @@ impl RenderHtml for InertElement { let el = crate::renderer::types::Element::cast_from(cursor.current()) .unwrap(); position.set(Position::NextChild); - el + InertElementState(self.html, el) } } diff --git a/tachys/src/renderer/dom.rs b/tachys/src/renderer/dom.rs index 11addfc7d5..bcac94fe52 100644 --- a/tachys/src/renderer/dom.rs +++ b/tachys/src/renderer/dom.rs @@ -444,7 +444,8 @@ impl Dom { // TODO can be optimized to cache HTML strings or cache