Merge pull request #1551 from ealmloff/fix-signals-outside-of-runtime

Fix using signals outside of a scope
This commit is contained in:
Jonathan Kelley authored and GitHub committed 2023-10-23 15:32:12 -04:00
commit ea8c5e290d
4 files changed
+32 -13

No files matched your search

+1 -1
View File
@@ -153,7 +153,7 @@ fn get_asset_root() -> Option<PathBuf> {
/// Get the mime type from a path-like string /// Get the mime type from a path-like string
fn get_mime_from_path(trimmed: &Path) -> Result<&'static str> { fn get_mime_from_path(trimmed: &Path) -> Result<&'static str> {
if trimmed.ends_with(".svg") { if trimmed.extension().is_some_and(|ext| ext == "svg") {
return Ok("image/svg+xml"); return Ok("image/svg+xml");
} }
+22 -8
View File
@@ -1,16 +1,28 @@
use core::{self, fmt::Debug}; use core::{self, fmt::Debug};
use std::cell::RefCell;
use std::fmt::{self, Formatter}; use std::fmt::{self, Formatter};
use std::rc::Rc;
// //
use dioxus_core::prelude::*; use dioxus_core::prelude::*;
use crate::use_signal; use crate::use_signal;
use crate::{dependency::Dependency, CopyValue}; use crate::{dependency::Dependency, CopyValue};
#[derive(Default, Clone)] #[derive(Copy, Clone, PartialEq)]
pub(crate) struct EffectStack { 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 { pub(crate) fn get_effect_stack() -> EffectStack {
@@ -18,7 +30,7 @@ pub(crate) fn get_effect_stack() -> EffectStack {
Some(rt) => rt, Some(rt) => rt,
None => { None => {
let store = EffectStack::default(); let store = EffectStack::default();
provide_root_context(store.clone()); provide_root_context(store);
store store
} }
} }
@@ -57,6 +69,7 @@ pub fn use_effect_with_dependencies<D: Dependency>(
pub struct Effect { pub struct Effect {
pub(crate) source: ScopeId, pub(crate) source: ScopeId,
pub(crate) callback: CopyValue<Box<dyn FnMut()>>, pub(crate) callback: CopyValue<Box<dyn FnMut()>>,
pub(crate) effect_stack: EffectStack,
} }
impl Debug for Effect { impl Debug for Effect {
@@ -67,7 +80,7 @@ impl Debug for Effect {
impl Effect { impl Effect {
pub(crate) fn current() -> Option<Self> { 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. /// 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 { let myself = Self {
source: current_scope_id().expect("in a virtual dom"), source: current_scope_id().expect("in a virtual dom"),
callback: CopyValue::new(Box::new(callback)), callback: CopyValue::new(Box::new(callback)),
effect_stack: get_effect_stack(),
}; };
myself.try_run(); myself.try_run();
@@ -88,11 +102,11 @@ impl Effect {
pub fn try_run(&self) { pub fn try_run(&self) {
if let Some(mut callback) = self.callback.try_write() { 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(); callback();
{ {
get_effect_stack().effects.borrow_mut().pop(); self.effect_stack.effects.write().pop();
} }
} }
} }
+4 -2
View File
@@ -78,19 +78,21 @@ pub fn selector<R: PartialEq>(mut f: impl FnMut() -> R + 'static) -> ReadOnlySig
let effect = Effect { let effect = Effect {
source: current_scope_id().expect("in a virtual dom"), source: current_scope_id().expect("in a virtual dom"),
callback: CopyValue::invalid(), 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 { state.inner.value.set(SignalData {
subscribers: Default::default(), subscribers: Default::default(),
effect_subscribers: Default::default(), effect_subscribers: Default::default(),
update_any: schedule_update_any().expect("in a virtual dom"), update_any: schedule_update_any().expect("in a virtual dom"),
value: f(), 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 || { effect.callback.value.set(Box::new(move || {
+5 -2
View File
@@ -11,7 +11,7 @@ use dioxus_core::{
ScopeId, ScopeState, 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. /// 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) subscribers: Rc<RefCell<Vec<ScopeId>>>,
pub(crate) effect_subscribers: Rc<RefCell<Vec<Effect>>>, pub(crate) effect_subscribers: Rc<RefCell<Vec<Effect>>>,
pub(crate) update_any: Arc<dyn Fn(ScopeId)>, pub(crate) update_any: Arc<dyn Fn(ScopeId)>,
pub(crate) effect_stack: EffectStack,
pub(crate) value: T, pub(crate) value: T,
} }
@@ -144,6 +145,7 @@ impl<T: 'static> Signal<T> {
effect_subscribers: Default::default(), effect_subscribers: Default::default(),
update_any: schedule_update_any().expect("in a virtual dom"), update_any: schedule_update_any().expect("in a virtual dom"),
value, value,
effect_stack: get_effect_stack(),
}), }),
} }
} }
@@ -157,6 +159,7 @@ impl<T: 'static> Signal<T> {
effect_subscribers: Default::default(), effect_subscribers: Default::default(),
update_any: schedule_update_any().expect("in a virtual dom"), update_any: schedule_update_any().expect("in a virtual dom"),
value, value,
effect_stack: get_effect_stack(),
}, },
owner, owner,
), ),
@@ -172,7 +175,7 @@ impl<T: 'static> Signal<T> {
/// If the signal has been dropped, this will panic. /// If the signal has been dropped, this will panic.
pub fn read(&self) -> Ref<T> { pub fn read(&self) -> Ref<T> {
let inner = self.inner.read(); 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(); let mut effect_subscribers = inner.effect_subscribers.borrow_mut();
if !effect_subscribers.contains(&effect) { if !effect_subscribers.contains(&effect) {
effect_subscribers.push(effect); effect_subscribers.push(effect);