effect

Macro effect 

Source
macro_rules! effect {
    ($f:expr) => { ... };
    ($f:expr, $f2:expr) => { ... };
}
Expand description

Creates a reactive effect from a closure (and optionally a dependency collector).

The effect! macro is a convenient wrapper around [reactive_cache::Effect::new] and [reactive_cache::Effect::new_with_deps]. It allows you to quickly register a reactive effect that automatically tracks dependencies and re-runs when they change.

§Forms

  • effect!(f)
    Equivalent to calling [Effect::new(f)]. In this form, dependencies are automatically tracked while executing f.

  • effect!(f, deps)
    Equivalent to calling [Effect::new_with_deps(f, deps)]. In this form, dependency tracking is performed only when running deps, not f. The closure f will still be executed when dependencies change, but its execution does not collect new dependencies.

§Requirements

  • f must be a closure or function pointer that takes no arguments and returns ().
  • deps (if provided) must also be a closure or function pointer taking no arguments and returning ().

§Examples

use std::{cell::Cell, rc::Rc};
use reactive_cache::effect;
use reactive_macros::{ref_signal, signal};

signal!(static mut A: i32 = 1;);

// Track effect runs
let counter = Rc::new(Cell::new(0));
let counter_clone = counter.clone();

// `effect!(f)` form
let e = effect!(move || {
    let _ = A();           // reading the signal
    counter_clone.set(counter_clone.get() + 1); // increment effect counter
});

let ptr = Rc::into_raw(e); // actively leak to avoid implicitly dropping the effect

// Effect runs immediately upon creation
assert_eq!(counter.get(), 1);

// Changing A triggers the effect again
assert!(A_set(10));
assert_eq!(counter.get(), 2);

// Setting the same value does NOT trigger the effect
assert!(!A_set(10));
assert_eq!(counter.get(), 2);

// `effect!(f, deps)` form
let _ = effect!(
    || println!("effect body"),
    || println!("dependency collector")
);

§SAFETY

The macro internally uses [reactive_cache::Effect], which relies on static tracking and is not thread-safe. Only use in single-threaded contexts.

§Warning

Do not set any signal that is part of the same effect chain.

Effects automatically run whenever one of their dependent signals changes. If an effect modifies a signal that it (directly or indirectly) observes, it creates a circular dependency. This can lead to:

  • an infinite loop of updates, or
  • conflicting updates that the system cannot resolve.

In the general case, it is impossible to automatically determine whether such an effect will ever terminate—this is essentially a version of the halting problem. Therefore, you must ensure manually that effects do not update signals within their own dependency chain.