2023-08-07 19:32:46 +00:00
|
|
|
use core::{self, fmt::Debug};
|
2023-08-08 20:18:15 +00:00
|
|
|
use std::cell::RefCell;
|
2023-08-07 19:32:46 +00:00
|
|
|
use std::fmt::{self, Formatter};
|
2023-08-08 20:18:15 +00:00
|
|
|
use std::rc::Rc;
|
|
|
|
//
|
2023-08-05 00:23:57 +00:00
|
|
|
use dioxus_core::prelude::*;
|
|
|
|
|
2023-08-08 20:18:15 +00:00
|
|
|
use crate::use_signal;
|
2023-08-08 20:06:33 +00:00
|
|
|
use crate::{dependency::Dependency, CopyValue};
|
2023-08-05 00:23:57 +00:00
|
|
|
|
2023-08-08 20:18:15 +00:00
|
|
|
#[derive(Default, Clone)]
|
2023-08-05 00:23:57 +00:00
|
|
|
pub(crate) struct EffectStack {
|
2023-08-08 20:18:15 +00:00
|
|
|
pub(crate) effects: Rc<RefCell<Vec<Effect>>>,
|
2023-08-05 00:23:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn get_effect_stack() -> EffectStack {
|
|
|
|
match consume_context() {
|
|
|
|
Some(rt) => rt,
|
|
|
|
None => {
|
|
|
|
let store = EffectStack::default();
|
|
|
|
provide_root_context(store).expect("in a virtual dom")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-07 23:56:49 +00:00
|
|
|
/// Create a new effect. The effect will be run immediately and whenever any signal it reads changes.
|
|
|
|
/// The signal will be owned by the current component and will be dropped when the component is dropped.
|
|
|
|
pub fn use_effect(cx: &ScopeState, callback: impl FnMut() + 'static) {
|
|
|
|
cx.use_hook(|| Effect::new(callback));
|
|
|
|
}
|
|
|
|
|
2023-08-08 20:06:33 +00:00
|
|
|
/// Create a new effect. The effect will be run immediately and whenever any signal it reads changes.
|
|
|
|
/// The signal will be owned by the current component and will be dropped when the component is dropped.
|
|
|
|
pub fn use_effect_with_dependencies<D: Dependency>(
|
|
|
|
cx: &ScopeState,
|
|
|
|
dependencies: D,
|
|
|
|
mut callback: impl FnMut(D::Out) + 'static,
|
|
|
|
) where
|
|
|
|
D::Out: 'static,
|
|
|
|
{
|
|
|
|
let dependencies_signal = use_signal(cx, || dependencies.out());
|
|
|
|
cx.use_hook(|| {
|
|
|
|
Effect::new(move || {
|
|
|
|
let deref = &*dependencies_signal.read();
|
|
|
|
callback(deref.clone());
|
|
|
|
});
|
|
|
|
});
|
|
|
|
let changed = { dependencies.changed(&*dependencies_signal.read()) };
|
|
|
|
if changed {
|
|
|
|
dependencies_signal.set(dependencies.out());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-07 23:56:49 +00:00
|
|
|
/// Effects allow you to run code when a signal changes. Effects are run immediately and whenever any signal it reads changes.
|
2023-08-05 00:23:57 +00:00
|
|
|
#[derive(Copy, Clone, PartialEq)]
|
|
|
|
pub struct Effect {
|
2023-08-21 19:42:56 +00:00
|
|
|
pub(crate) source: ScopeId,
|
2023-08-07 19:32:46 +00:00
|
|
|
pub(crate) callback: CopyValue<Box<dyn FnMut()>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Debug for Effect {
|
|
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
|
|
f.write_fmt(format_args!("{:?}", self.callback.value))
|
|
|
|
}
|
2023-08-05 00:23:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Effect {
|
|
|
|
pub(crate) fn current() -> Option<Self> {
|
2023-08-08 20:18:15 +00:00
|
|
|
get_effect_stack().effects.borrow().last().copied()
|
2023-08-05 00:23:57 +00:00
|
|
|
}
|
|
|
|
|
2023-08-07 23:56:49 +00:00
|
|
|
/// Create a new effect. The effect will be run immediately and whenever any signal it reads changes.
|
|
|
|
///
|
|
|
|
/// The signal will be owned by the current component and will be dropped when the component is dropped.
|
2023-08-05 00:23:57 +00:00
|
|
|
pub fn new(callback: impl FnMut() + 'static) -> Self {
|
|
|
|
let myself = Self {
|
2023-08-21 19:42:56 +00:00
|
|
|
source: current_scope_id().expect("in a virtual dom"),
|
2023-08-05 00:23:57 +00:00
|
|
|
callback: CopyValue::new(Box::new(callback)),
|
|
|
|
};
|
|
|
|
|
|
|
|
myself.try_run();
|
|
|
|
|
|
|
|
myself
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Run the effect callback immediately. Returns `true` if the effect was run. Returns `false` is the effect is dead.
|
|
|
|
pub fn try_run(&self) {
|
|
|
|
if let Some(mut callback) = self.callback.try_write() {
|
|
|
|
{
|
2023-08-08 20:18:15 +00:00
|
|
|
get_effect_stack().effects.borrow_mut().push(*self);
|
2023-08-05 00:23:57 +00:00
|
|
|
}
|
|
|
|
callback();
|
|
|
|
{
|
2023-08-08 20:18:15 +00:00
|
|
|
get_effect_stack().effects.borrow_mut().pop();
|
2023-08-05 00:23:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|