askill
signalize-effects

signalize-effectsSafety 95Repository

Reactive side effects for @spearwolf/signalize: createEffect, cleanup callbacks, dependency tracking (dynamic and static), effect priority, autorun options, nested effects. Use when creating effects that react to signal changes.

32 stars
1.2k downloads
Updated 2/6/2026

Package Files

Loading files...
SKILL.md

Signalize Effects

Quick Start

import {createEffect, createSignal} from '@spearwolf/signalize';

const count = createSignal(0);

const effect = createEffect(() => {
  console.log('Count:', count.get());
});

count.set(1); // Logs: "Count: 1"
effect.destroy(); // Cleanup and stop

Cleanup Callbacks (Critical!)

Return a function from your effect to handle cleanup. This is essential for managing resources like timers, subscriptions, or event listeners.

createEffect(() => {
  const timer = setInterval(() => tick(), 1000);

  // Called BEFORE every re-run AND on destroy
  return () => clearInterval(timer);
});

When cleanup runs:

EventCleanup Called
Dependency changes (before re-run)YES
effect.destroy()YES
Signal destroyed (last dependency)YES
Multiple destroy() callsOnly first time

See references/cleanup.md for comprehensive patterns.

Dynamic vs Static Effects

Dynamic Effects (Default)

Dependencies are recalculated on every run based on which signals are read:

createEffect(() => {
  if (showDetails.get()) {
    console.log(details.get()); // Only tracked when showDetails is true
  } else {
    console.log(summary.get()); // Only tracked when showDetails is false
  }
});
// Dependencies CHANGE based on showDetails value

Characteristics:

  • Runs immediately on creation
  • Dependencies can change between runs
  • Most flexible, recommended for most cases

Static Effects

Dependencies are fixed at creation time:

createEffect(() => {
  console.log(a.get(), b.get());
}, [a, b]); // Explicit dependency array

Characteristics:

  • Does NOT run immediately
  • Dependencies never change
  • Call .run() if you need initial execution
const effect = createEffect(callback, [a, b]);
effect.run(); // Manual initial run if needed

See references/dynamic-static.md for detailed comparison.

Effect Options

createEffect(callback, options?)
createEffect(callback, dependencies, options?)
OptionTypeDefaultDescription
autorunbooleantrueRun immediately on creation
prioritynumber0Execution order (higher = first)
attachobject | SignalGroup-Attach to group for lifecycle

autorun: false

const effect = createEffect(
  () => {
    console.log(signal.get());
  },
  {autorun: false},
);

// Effect not running yet
signal.set(1); // Still not running

effect.run(); // NOW it runs and starts tracking

Very useful when you need to precisely control when an effect callback should run, e.g., only within an animation frame.

priority

Higher priority effects run first:

createEffect(first, {priority: 1000}); // Runs first
createEffect(second, {priority: 0}); // Runs second (default)
createEffect(last, {priority: -100}); // Runs last

Default priorities:

  • Memos: 1000 (run before effects)
  • Effects: 0

This ensures memos compute before effects that depend on them.

HINT: The priority also influences the effect execution order after batching.

Nested Effects

Effects can create other effects. Inner effects are isolated from outer:

createEffect(() => {
  console.log('Outer:', a.get());

  createEffect(() => {
    console.log('Inner:', b.get());
    return () => console.log('Inner cleanup');
  });

  return () => console.log('Outer cleanup');
});

Critical behavior: When outer effect re-runs, inner effects are destroyed (cleanup called) and recreated.

  • Outer cleanup runs first
  • Then all child effect cleanups run
  • Then outer callback executes (recreating child effects)

See references/cleanup.md for nested cleanup patterns.

Effect Methods

MethodDescription
effect.run()Manually trigger execution
effect.destroy()Stop effect and run cleanup

Lifecycle Hooks

Subscribe to global effect events:

IMPORTANT: Please only use if there is no other solution, as these global hooks can cause performance issues. They are originally intended for testing purposes only.

import {onCreateEffect, onDestroyEffect} from '@spearwolf/signalize';

const unsubCreate = onCreateEffect((effect) => {
  console.log('Effect created');
});

const unsubDestroy = onDestroyEffect((effect) => {
  console.log('Effect destroyed');
});

// Later: unsubscribe
unsubCreate();
unsubDestroy();

See references/lifecycle.md for details.

Common Patterns

Resource Management

createEffect(() => {
  const subscription = api.subscribe(topic.get());
  return () => subscription.unsubscribe();
});

DOM Updates

createEffect(() => {
  element.textContent = message.get();
});

Derived Actions

createEffect(() => {
  if (isLoggedIn.get()) {
    loadUserData();
  } else {
    clearUserData();
  }
});

Pitfalls to Avoid

1. Missing cleanup for resources

// BAD - memory leak!
createEffect(() => {
  setInterval(() => tick(), 1000);
});

// GOOD
createEffect(() => {
  const id = setInterval(() => tick(), 1000);
  return () => clearInterval(id);
});

2. Expecting static effect to run initially

// This does NOT run on creation
createEffect(callback, [a, b]);

// Add .run() if needed
createEffect(callback, [a, b]).run();

3. Reading signal with .value in effect

// BAD - no dependency tracking
createEffect(() => {
  console.log(signal.value); // Won't re-run on change!
});

// GOOD
createEffect(() => {
  console.log(signal.get());
});

For detailed patterns, see:

See Also

Install

Download ZIP
Requires askill CLI v1.0+

AI Quality Score

95/100Analyzed 2/11/2026

An exceptionally well-documented skill for managing reactive effects in the Signalize library, featuring clear examples, lifecycle details, and critical safety warnings.

95
98
85
98
95

Metadata

Licenseunknown
Version-
Updated2/6/2026
Publisherspearwolf

Tags

api