Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix using signals outside of a scope #1551

Merged
merged 2 commits into from
Oct 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/desktop/src/protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ fn get_asset_root() -> Option<PathBuf> {

/// Get the mime type from a path-like string
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");
}

Expand Down
30 changes: 22 additions & 8 deletions packages/signals/src/effect.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,36 @@
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 {
match consume_context() {
Some(rt) => rt,
None => {
let store = EffectStack::default();
provide_root_context(store.clone());
provide_root_context(store);
store
}
}
Expand Down Expand Up @@ -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 {
Expand All @@ -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.
Expand All @@ -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();
Expand All @@ -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();
}
}
}
Expand Down
6 changes: 4 additions & 2 deletions packages/signals/src/selector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 || {
Expand Down
7 changes: 5 additions & 2 deletions packages/signals/src/signal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand Down Expand Up @@ -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,
}

Expand Down Expand Up @@ -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(),
}),
}
}
Expand All @@ -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,
),
Expand All @@ -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);
Expand Down
Loading