Browse Source

don't subscribe in tasks or event handlers

Evan Almloff 1 year ago
parent
commit
0c17bdb737

+ 5 - 4
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

+ 4 - 1
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<Vec<ScopeId>>,
+    pub(crate) rendering: Cell<bool>,
 }
 
 impl Runtime {
@@ -57,6 +58,8 @@ impl Runtime {
             scope_contexts: Default::default(),
 
             scope_stack: Default::default(),
+
+            rendering: Cell::new(true),
         });
         runtime
     }

+ 2 - 0
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);
     }
 }

+ 6 - 0
packages/core/src/scope_context.rs

@@ -263,6 +263,12 @@ pub fn current_scope_id() -> Option<ScopeId> {
     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<T: 'static + Clone>() -> Option<T> {
     with_current_scope(|cx| cx.consume_context::<T>()).flatten()

+ 4 - 0
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;
                             }

+ 14 - 11
packages/signals/src/signal.rs

@@ -109,17 +109,20 @@ impl<T: 'static> Signal<T> {
                 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(&current_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(&current_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)