Quellcode durchsuchen

effect-outside-of-runtime

Evan Almloff vor 1 Jahr
Ursprung
Commit
050add21d7
3 geänderte Dateien mit 30 neuen und 11 gelöschten Zeilen
  1. 21 7
      packages/signals/src/effect.rs
  2. 4 2
      packages/signals/src/selector.rs
  3. 5 2
      packages/signals/src/signal.rs

+ 21 - 7
packages/signals/src/effect.rs

@@ -1,16 +1,28 @@
 use core::{self, fmt::Debug};
-use std::cell::RefCell;
 use std::fmt::{self, Formatter};
-use std::rc::Rc;
 //
 use dioxus_core::prelude::*;
 
 use crate::use_signal;
 use crate::{dependency::Dependency, CopyValue};
 
-#[derive(Default, Clone)]
+#[derive(Copy, Clone, PartialEq)]
 pub(crate) struct EffectStack {
-    pub(crate) effects: Rc<RefCell<Vec<Effect>>>,
+    pub(crate) effects: CopyValue<Vec<Effect>>,
+}
+
+impl Default for EffectStack {
+    fn default() -> Self {
+        Self {
+            effects: CopyValue::new_in_scope(Vec::new(), ScopeId::ROOT),
+        }
+    }
+}
+
+impl EffectStack {
+    pub(crate) fn current(&self) -> Option<Effect> {
+        self.effects.read().last().copied()
+    }
 }
 
 pub(crate) fn get_effect_stack() -> EffectStack {
@@ -57,6 +69,7 @@ pub fn use_effect_with_dependencies<D: Dependency>(
 pub struct Effect {
     pub(crate) source: ScopeId,
     pub(crate) callback: CopyValue<Box<dyn FnMut()>>,
+    pub(crate) effect_stack: EffectStack,
 }
 
 impl Debug for Effect {
@@ -67,7 +80,7 @@ impl Debug for Effect {
 
 impl Effect {
     pub(crate) fn current() -> Option<Self> {
-        get_effect_stack().effects.borrow().last().copied()
+        get_effect_stack().effects.read().last().copied()
     }
 
     /// Create a new effect. The effect will be run immediately and whenever any signal it reads changes.
@@ -77,6 +90,7 @@ impl Effect {
         let myself = Self {
             source: current_scope_id().expect("in a virtual dom"),
             callback: CopyValue::new(Box::new(callback)),
+            effect_stack: get_effect_stack(),
         };
 
         myself.try_run();
@@ -88,11 +102,11 @@ impl Effect {
     pub fn try_run(&self) {
         if let Some(mut callback) = self.callback.try_write() {
             {
-                get_effect_stack().effects.borrow_mut().push(*self);
+                self.effect_stack.effects.write().push(*self);
             }
             callback();
             {
-                get_effect_stack().effects.borrow_mut().pop();
+                self.effect_stack.effects.write().pop();
             }
         }
     }

+ 4 - 2
packages/signals/src/selector.rs

@@ -78,19 +78,21 @@ pub fn selector<R: PartialEq>(mut f: impl FnMut() -> R + 'static) -> ReadOnlySig
     let effect = Effect {
         source: current_scope_id().expect("in a virtual dom"),
         callback: CopyValue::invalid(),
+        effect_stack: get_effect_stack(),
     };
 
     {
-        get_effect_stack().effects.borrow_mut().push(effect);
+        get_effect_stack().effects.write().push(effect);
     }
     state.inner.value.set(SignalData {
         subscribers: Default::default(),
         effect_subscribers: Default::default(),
         update_any: schedule_update_any().expect("in a virtual dom"),
         value: f(),
+        effect_stack: get_effect_stack(),
     });
     {
-        get_effect_stack().effects.borrow_mut().pop();
+        get_effect_stack().effects.write().pop();
     }
 
     effect.callback.value.set(Box::new(move || {

+ 5 - 2
packages/signals/src/signal.rs

@@ -11,7 +11,7 @@ use dioxus_core::{
     ScopeId, ScopeState,
 };
 
-use crate::{CopyValue, Effect};
+use crate::{get_effect_stack, CopyValue, Effect, EffectStack};
 
 /// Creates a new Signal. Signals are a Copy state management solution with automatic dependency tracking.
 ///
@@ -82,6 +82,7 @@ pub(crate) struct SignalData<T> {
     pub(crate) subscribers: Rc<RefCell<Vec<ScopeId>>>,
     pub(crate) effect_subscribers: Rc<RefCell<Vec<Effect>>>,
     pub(crate) update_any: Arc<dyn Fn(ScopeId)>,
+    pub(crate) effect_stack: EffectStack,
     pub(crate) value: T,
 }
 
@@ -144,6 +145,7 @@ impl<T: 'static> Signal<T> {
                 effect_subscribers: Default::default(),
                 update_any: schedule_update_any().expect("in a virtual dom"),
                 value,
+                effect_stack: get_effect_stack(),
             }),
         }
     }
@@ -157,6 +159,7 @@ impl<T: 'static> Signal<T> {
                     effect_subscribers: Default::default(),
                     update_any: schedule_update_any().expect("in a virtual dom"),
                     value,
+                    effect_stack: get_effect_stack(),
                 },
                 owner,
             ),
@@ -172,7 +175,7 @@ impl<T: 'static> Signal<T> {
     /// If the signal has been dropped, this will panic.
     pub fn read(&self) -> Ref<T> {
         let inner = self.inner.read();
-        if let Some(effect) = Effect::current() {
+        if let Some(effect) = inner.effect_stack.current() {
             let mut effect_subscribers = inner.effect_subscribers.borrow_mut();
             if !effect_subscribers.contains(&effect) {
                 effect_subscribers.push(effect);