Don't move over event handler fields when diffing props (#2129)

* don't move over event handler fields when diffing props

* Expand values_memoize_in_place test to cover the new bug case
This commit is contained in:
Evan Almloff authored and GitHub committed 2024-03-22 15:18:38 -07:00
1 parent 0662033c84
commit b19a546c0a
2 files changed
+34 -6

No files matched your search

+19 -4
View File
@@ -641,6 +641,15 @@ mod struct_info {
}) })
.collect(); .collect();
let regular_fields: Vec<_> = self
.included_fields()
.filter(|f| !looks_like_signal_type(f.ty) && !looks_like_event_handler_type(f.ty))
.map(|f| {
let name = f.name;
quote!(#name)
})
.collect();
let move_event_handlers = quote! { let move_event_handlers = quote! {
#( #(
// Update the event handlers // Update the event handlers
@@ -668,9 +677,12 @@ mod struct_info {
// NOTE: we don't compare other fields individually because we want to let users opt-out of memoization for certain fields by implementing PartialEq themselves // NOTE: we don't compare other fields individually because we want to let users opt-out of memoization for certain fields by implementing PartialEq themselves
let non_signal_fields_equal = self == new; let non_signal_fields_equal = self == new;
// If they are not equal, we need to move over all the fields to self // If they are not equal, we need to move over all the fields that are not event handlers or signals to self
if !non_signal_fields_equal { if !non_signal_fields_equal {
*self = new.clone(); let new_clone = new.clone();
#(
self.#regular_fields = new_clone.#regular_fields;
)*
} }
// Move any signal and event fields into their old container. // Move any signal and event fields into their old container.
// We update signals and event handlers in place so that they are always up to date even if they were moved into a future in a previous render // We update signals and event handlers in place so that they are always up to date even if they were moved into a future in a previous render
@@ -684,9 +696,12 @@ mod struct_info {
let equal = self == new; let equal = self == new;
// Move any signal and event fields into their old container. // Move any signal and event fields into their old container.
#move_event_handlers #move_event_handlers
// If they are not equal, we need to move over all the fields to self // If they are not equal, we need to move over all the fields that are not event handlers to self
if !equal { if !equal {
*self = new.clone(); let new_clone = new.clone();
#(
self.#regular_fields = new_clone.#regular_fields;
)*
} }
equal equal
}) })
@@ -1,4 +1,6 @@
use dioxus::prelude::*; use dioxus::prelude::*;
use dioxus_core::ElementId;
use std::rc::Rc;
thread_local! { thread_local! {
static DROP_COUNT: std::cell::RefCell<usize> = const { std::cell::RefCell::new(0) }; static DROP_COUNT: std::cell::RefCell<usize> = const { std::cell::RefCell::new(0) };
@@ -6,11 +8,19 @@ thread_local! {
#[test] #[test]
fn values_memoize_in_place() { fn values_memoize_in_place() {
set_event_converter(Box::new(dioxus::html::SerializedHtmlEventConverter));
let mut dom = VirtualDom::new(app); let mut dom = VirtualDom::new(app);
dom.rebuild_in_place(); let mutations = dom.rebuild_to_vec();
println!("{:#?}", mutations);
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
for _ in 0..20 { for _ in 0..20 {
dom.handle_event(
"click",
Rc::new(PlatformEventData::new(Box::<SerializedMouseData>::default())),
ElementId(1),
true,
);
dom.render_immediate(&mut dioxus_core::NoOpMutations); dom.render_immediate(&mut dioxus_core::NoOpMutations);
} }
dom.render_immediate(&mut dioxus_core::NoOpMutations); dom.render_immediate(&mut dioxus_core::NoOpMutations);
@@ -57,7 +67,10 @@ fn TakesEventHandler(click: EventHandler<usize>, children: usize) -> Element {
} }
rsx! { rsx! {
button { "{children}" } button {
onclick: move |_| click(children),
"{children}"
}
} }
} }