From 0c17bdb73753443c0c4f57e8b2eb3f6c750d386f Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 7 Aug 2023 17:55:29 -0700 Subject: [PATCH] don't subscribe in tasks or event handlers --- packages/core/src/lib.rs | 9 +++++---- packages/core/src/runtime.rs | 5 ++++- packages/core/src/scheduler/wait.rs | 2 ++ packages/core/src/scope_context.rs | 6 ++++++ packages/core/src/virtual_dom.rs | 4 ++++ packages/signals/src/signal.rs | 25 ++++++++++++++----------- 6 files changed, 35 insertions(+), 16 deletions(-) diff --git a/packages/core/src/lib.rs b/packages/core/src/lib.rs index 363be390d..62e142f60 100644 --- a/packages/core/src/lib.rs +++ b/packages/core/src/lib.rs @@ -73,10 +73,11 @@ pub(crate) mod innerlude { } pub use crate::innerlude::{ - fc_to_builder, AnyValue, Attribute, AttributeValue, BorrowedAttributeValue, CapturedError, - Component, DynamicNode, Element, ElementId, Event, Fragment, IntoDynNode, LazyNodes, Mutation, - Mutations, Properties, RenderReturn, Scope, ScopeId, ScopeState, Scoped, TaskId, Template, - TemplateAttribute, TemplateNode, VComponent, VNode, VPlaceholder, VText, VirtualDom, + fc_to_builder, vdom_is_rendering, AnyValue, Attribute, AttributeValue, BorrowedAttributeValue, + CapturedError, Component, DynamicNode, Element, ElementId, Event, Fragment, IntoDynNode, + LazyNodes, Mutation, Mutations, Properties, RenderReturn, Scope, ScopeId, ScopeState, Scoped, + TaskId, Template, TemplateAttribute, TemplateNode, VComponent, VNode, VPlaceholder, VText, + VirtualDom, }; /// The purpose of this module is to alleviate imports of many common types diff --git a/packages/core/src/runtime.rs b/packages/core/src/runtime.rs index 89de770c5..9f031f287 100644 --- a/packages/core/src/runtime.rs +++ b/packages/core/src/runtime.rs @@ -1,4 +1,4 @@ -use std::cell::{Ref, RefCell}; +use std::cell::{Cell, Ref, RefCell}; use crate::{innerlude::Scheduler, scope_context::ScopeContext, scopes::ScopeId}; use std::rc::Rc; @@ -47,6 +47,7 @@ pub struct Runtime { // We use this to track the current scope pub(crate) scope_stack: RefCell>, + pub(crate) rendering: Cell, } impl Runtime { @@ -57,6 +58,8 @@ impl Runtime { scope_contexts: Default::default(), scope_stack: Default::default(), + + rendering: Cell::new(true), }); runtime } diff --git a/packages/core/src/scheduler/wait.rs b/packages/core/src/scheduler/wait.rs index 62fa10180..625873293 100644 --- a/packages/core/src/scheduler/wait.rs +++ b/packages/core/src/scheduler/wait.rs @@ -20,6 +20,7 @@ impl VirtualDom { // update the scope stack self.runtime.scope_stack.borrow_mut().push(task.scope); + self.runtime.rendering.set(false); // If the task completes... if task.task.borrow_mut().as_mut().poll(&mut cx).is_ready() { @@ -33,5 +34,6 @@ impl VirtualDom { // Remove the scope from the stack self.runtime.scope_stack.borrow_mut().pop(); + self.runtime.rendering.set(true); } } diff --git a/packages/core/src/scope_context.rs b/packages/core/src/scope_context.rs index 36c864117..82b3fd4e2 100644 --- a/packages/core/src/scope_context.rs +++ b/packages/core/src/scope_context.rs @@ -263,6 +263,12 @@ pub fn current_scope_id() -> Option { with_runtime(|rt| rt.current_scope_id()).flatten() } +#[doc(hidden)] +/// Check if the virtual dom is currently inside of the body of a component +pub fn vdom_is_rendering() -> bool { + with_runtime(|rt| rt.rendering.get()).unwrap_or_default() +} + /// Consume context from the current scope pub fn consume_context() -> Option { with_current_scope(|cx| cx.consume_context::()).flatten() diff --git a/packages/core/src/virtual_dom.rs b/packages/core/src/virtual_dom.rs index 0a4577f4c..a1def71d2 100644 --- a/packages/core/src/virtual_dom.rs +++ b/packages/core/src/virtual_dom.rs @@ -392,10 +392,12 @@ impl VirtualDom { if let AttributeValue::Listener(listener) = listener { let origin = el_ref.scope; self.runtime.scope_stack.borrow_mut().push(origin); + self.runtime.rendering.set(false); if let Some(cb) = listener.borrow_mut().as_deref_mut() { cb(uievent.clone()); } self.runtime.scope_stack.borrow_mut().pop(); + self.runtime.rendering.set(true); if !uievent.propagates.get() { return; @@ -426,10 +428,12 @@ impl VirtualDom { if let AttributeValue::Listener(listener) = &attr.value { let origin = el_ref.scope; self.runtime.scope_stack.borrow_mut().push(origin); + self.runtime.rendering.set(false); if let Some(cb) = listener.borrow_mut().as_deref_mut() { cb(uievent.clone()); } self.runtime.scope_stack.borrow_mut().pop(); + self.runtime.rendering.set(true); break; } diff --git a/packages/signals/src/signal.rs b/packages/signals/src/signal.rs index 698ac8e12..8d2275b41 100644 --- a/packages/signals/src/signal.rs +++ b/packages/signals/src/signal.rs @@ -109,17 +109,20 @@ impl Signal { effect_subscribers.push(effect); } } else if let Some(current_scope_id) = current_scope_id() { - log::trace!( - "{:?} subscribed to {:?}", - self.inner.value, - current_scope_id - ); - let mut subscribers = inner.subscribers.borrow_mut(); - if !subscribers.contains(¤t_scope_id) { - subscribers.push(current_scope_id); - drop(subscribers); - let unsubscriber = current_unsubscriber(); - inner.subscribers.borrow_mut().push(unsubscriber.scope); + // only subscribe if the vdom is rendering + if dioxus_core::vdom_is_rendering() { + log::trace!( + "{:?} subscribed to {:?}", + self.inner.value, + current_scope_id + ); + let mut subscribers = inner.subscribers.borrow_mut(); + if !subscribers.contains(¤t_scope_id) { + subscribers.push(current_scope_id); + drop(subscribers); + let unsubscriber = current_unsubscriber(); + inner.subscribers.borrow_mut().push(unsubscriber.scope); + } } } Ref::map(inner, |v| &v.value)