1
0
Эх сурвалжийг харах

Merge pull request #1386 from ealmloff/fix-new-signals-in-effects

Fix leaked signals created in effects
Jonathan Kelley 1 жил өмнө
parent
commit
30b958ffa8

+ 4 - 1
packages/signals/src/effect.rs

@@ -18,7 +18,8 @@ pub(crate) fn get_effect_stack() -> EffectStack {
         Some(rt) => rt,
         None => {
             let store = EffectStack::default();
-            provide_root_context(store).expect("in a virtual dom")
+            provide_root_context(store.clone());
+            store
         }
     }
 }
@@ -54,6 +55,7 @@ pub fn use_effect_with_dependencies<D: Dependency>(
 /// Effects allow you to run code when a signal changes. Effects are run immediately and whenever any signal it reads changes.
 #[derive(Copy, Clone, PartialEq)]
 pub struct Effect {
+    pub(crate) source: ScopeId,
     pub(crate) callback: CopyValue<Box<dyn FnMut()>>,
 }
 
@@ -73,6 +75,7 @@ impl Effect {
     /// The signal will be owned by the current component and will be dropped when the component is dropped.
     pub fn new(callback: impl FnMut() + 'static) -> Self {
         let myself = Self {
+            source: current_scope_id().expect("in a virtual dom"),
             callback: CopyValue::new(Box::new(callback)),
         };
 

+ 16 - 9
packages/signals/src/rt.rs

@@ -2,14 +2,13 @@ use std::cell::{Ref, RefMut};
 
 use std::rc::Rc;
 
-use dioxus_core::prelude::{
-    consume_context, consume_context_from_scope, current_scope_id, provide_context,
-    provide_context_to_scope, provide_root_context,
-};
+use dioxus_core::prelude::*;
 use dioxus_core::ScopeId;
 
 use generational_box::{GenerationalBox, Owner, Store};
 
+use crate::Effect;
+
 fn current_store() -> Store {
     match consume_context() {
         Some(rt) => rt,
@@ -21,12 +20,20 @@ fn current_store() -> Store {
 }
 
 fn current_owner() -> Rc<Owner> {
-    match consume_context() {
-        Some(rt) => rt,
-        None => {
-            let owner = Rc::new(current_store().owner());
-            provide_context(owner).expect("in a virtual dom")
+    match Effect::current() {
+        // If we are inside of an effect, we should use the owner of the effect as the owner of the value.
+        Some(effect) => {
+            let scope_id = effect.source;
+            owner_in_scope(scope_id)
         }
+        // Otherwise either get an owner from the current scope or create a new one.
+        None => match has_context() {
+            Some(rt) => rt,
+            None => {
+                let owner = Rc::new(current_store().owner());
+                provide_context(owner).expect("in a virtual dom")
+            }
+        },
     }
 }
 

+ 1 - 0
packages/signals/src/selector.rs

@@ -74,6 +74,7 @@ pub fn selector<R: PartialEq>(mut f: impl FnMut() -> R + 'static) -> ReadOnlySig
         inner: CopyValue::invalid(),
     };
     let effect = Effect {
+        source: current_scope_id().expect("in a virtual dom"),
         callback: CopyValue::invalid(),
     };