From 797e7492a1b9e188627ab7530a66607ba19376d6 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 24 Feb 2025 15:18:21 -0600 Subject: [PATCH] Fix hot reloading component removal with formatted attribute values (#3559) * Fix hot reloading component removal with formatted attribute values * fix semvar --- packages/core/src/hotreload_utils.rs | 30 +++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/packages/core/src/hotreload_utils.rs b/packages/core/src/hotreload_utils.rs index 84ad37de6..f258c579e 100644 --- a/packages/core/src/hotreload_utils.rs +++ b/packages/core/src/hotreload_utils.rs @@ -147,13 +147,30 @@ impl DynamicLiteralPool { } } + // TODO: This should be marked as private in the next major release pub fn get_component_property<'a, T>( &self, id: usize, hot_reload: &'a HotReloadedTemplate, f: impl FnOnce(&'a HotReloadLiteral) -> Option, ) -> Option { - f(hot_reload.component_values.get(id)?) + let value = hot_reload.component_values.get(id)?; + f(value) + } + + fn get_component_property_or_default<'a, T: Default>( + &self, + id: usize, + hot_reload: &'a HotReloadedTemplate, + f: impl FnOnce(&'a HotReloadLiteral) -> Option, + ) -> Option { + // If the component was removed since the last hot reload, the hot reload template may not + // have the property. If that is the case, just use a default value since the component is + // never rendered. + if id >= hot_reload.component_values.len() { + return Some(T::default()); + } + self.get_component_property(id, hot_reload, f) } /// Get a component property of a specific type at the component property index @@ -169,26 +186,25 @@ impl DynamicLiteralPool { *(Box::new(t) as Box).downcast::().unwrap() } let grab_float = || { - self.get_component_property(id, hot_reload, HotReloadLiteral::as_float).unwrap_or_else(|| { + self.get_component_property_or_default(id, hot_reload, HotReloadLiteral::as_float).unwrap_or_else(|| { tracing::error!("Expected a float component property, because the type was {}. The CLI gave the hot reloading engine a type of {:?}. This is probably caused by a bug in dioxus hot reloading. Please report this issue.", std::any::type_name::(), hot_reload.component_values.get(id)); Default::default() - - }) + }) }; let grab_int = || { - self.get_component_property(id, hot_reload, HotReloadLiteral::as_int).unwrap_or_else(|| { + self.get_component_property_or_default(id, hot_reload, HotReloadLiteral::as_int).unwrap_or_else(|| { tracing::error!("Expected a integer component property, because the type was {}. The CLI gave the hot reloading engine a type of {:?}. This is probably caused by a bug in dioxus hot reloading. Please report this issue.", std::any::type_name::(), hot_reload.component_values.get(id)); Default::default() }) }; let grab_bool = || { - self.get_component_property(id, hot_reload, HotReloadLiteral::as_bool).unwrap_or_else(|| { + self.get_component_property_or_default(id, hot_reload, HotReloadLiteral::as_bool).unwrap_or_else(|| { tracing::error!("Expected a bool component property, because the type was {}. The CLI gave the hot reloading engine a type of {:?}. This is probably caused by a bug in dioxus hot reloading. Please report this issue.", std::any::type_name::(), hot_reload.component_values.get(id)); Default::default() }) }; let grab_fmted = || { - self.get_component_property(id, hot_reload, |fmted| HotReloadLiteral::as_fmted(fmted).map(|segments| self.render_formatted(segments))).unwrap_or_else(|| { + self.get_component_property_or_default(id, hot_reload, |fmted| HotReloadLiteral::as_fmted(fmted).map(|segments| self.render_formatted(segments))).unwrap_or_else(|| { tracing::error!("Expected a string component property, because the type was {}. The CLI gave the hot reloading engine a type of {:?}. This is probably caused by a bug in dioxus hot reloading. Please report this issue.", std::any::type_name::(), hot_reload.component_values.get(id)); Default::default() })