Merge pull request #1551 from ealmloff/fix-signals-outside-of-runtime
Fix using signals outside of a scope
This commit is contained in:
4 files changed
+32
-13
No files matched your search
@@ -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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 || {
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
Reference in new issue
Block a user