dev-resources.site
for different kinds of informations.
Vanilla JS Signal implementation
Published at
12/15/2024
Categories
javascript
signals
Author
artydev
Author
7 person written this
artydev
open
This is a pure signal implementation in Javascript, an improved version by ChatGPT and Blackbox from the code provided in :
export class Signal extends EventTarget {
#value;
#listeners = new Set();
#isNotifying = false; // Flag to track if we are currently notifying listeners
get value() {
return this.#value;
}
set value(value) {
if (this.#value === value) return;
this.#value = value;
this.#notify();
}
constructor(value) {
super();
this.#value = value;
}
/**
* Registers an effect function that will be called when the signal changes.
* @param {Function} fn - The effect function to run on change.
* @returns {Function} A cleanup function to unregister the effect.
*/
effect(fn) {
const wrappedFn = () => {
try {
fn();
} catch (error) {
console.error("Effect error:", error);
}
};
wrappedFn(); // Run the effect once immediately
this.#listeners.add(wrappedFn);
this.addEventListener("change", wrappedFn);
return () => {
this.#listeners.delete(wrappedFn);
this.removeEventListener("change", wrappedFn);
};
}
#notify() {
if (this.#listeners.size > 0 && !this.#isNotifying) {
this.#isNotifying = true; // Set the flag to prevent re-entrance
queueMicrotask(() => {
this.dispatchEvent(new CustomEvent("change"));
this.#isNotifying = false; // Reset the flag after notifying
});
}
}
valueOf() {
return this.#value;
}
toString() {
return String(this.#value);
}
}
export class Computed extends Signal {
#fn;
#deps;
constructor(fn, deps) {
super(Computed.#computeInitialValue(fn, deps));
this.#fn = fn;
this.#deps = deps;
for (const dep of deps) {
if (dep instanceof Signal) {
dep.effect(() => this.#update());
} else {
console.warn("Computed dependency is not a Signal:", dep);
throw new TypeError("All dependencies must be instances of Signal.");
}
}
}
static #computeInitialValue(fn, deps) {
try {
return fn(...deps.map(dep => dep.value));
} catch (error) {
console.error("Error computing initial value of Computed:", error);
return undefined;
}
}
#update() {
try {
const newValue = this.#fn(...this.#deps.map(dep => dep.value));
if (this.value !== newValue) {
super.value = newValue; // Update using Signal's setter
}
} catch (error) {
console.error("Error updating Computed value:", error);
}
}
}
/**
* Creates a new Signal instance with the given initial value.
* @param {*} initialValue - The initial value of the signal.
* @returns {Signal} A new Signal instance.
*/
export const signal = (initialValue) => new Signal(initialValue);
/**
* Creates a new Computed instance that derives its value from the given function and dependencies.
* @param {Function} fn - The function to compute the value.
* @param {Signal[]} deps - An array of Signal instances that the computed value depends on.
* @returns {Computed} A new Computed instance.
*/
export const computed = (fn, deps) => new Computed(fn, deps);
signals Article's
30 articles in total
New in Angular: Bridging RxJS and Signals with toSignal!
read article
A Complete Solution for Receiving Signals with Built-in Http Service in Strategy
read article
Vanilla JS Signal implementation
currently reading
How I'm Using Signals to Make My React App Simpler
read article
Angular Migrating to Signals: A Paradigm Shift in Change Detection
read article
The Problems with Signals: A Tale of Power and Responsibility
read article
Angular Signals: From Zero to Hero
read article
Mutable Derivations in Reactivity
read article
Introducing Brisa: Full-stack Web Platform Framework 🔥
read article
Async Derivations in Reactivity
read article
Scheduling Derivations in Reactivity
read article
Exploring Angular's Change Detection: In-Depth Analysis
read article
Understanding Reactive Contexts in Angular 18
read article
New Free eBook: Angular Mastery: From Principles To Practice.
read article
What's new in Angular 18
read article
Using @HostBinding with Signals
read article
Angular Inputs and Single Source of Truth
read article
Angular Signal Queries with the viewChild() and contentChild() Functions
read article
Converting Observables to Signals in Angular
read article
Angular Signals: Best Practices
read article
Streamlining Communication: New Signals API in Angular 17.3
read article
Signal-Based Inputs and the Output Function
read article
What's new in Angular 17.3
read article
Master Angular 17.1 and 17.2
read article
Angular Computed Signal with an Observable
read article
Django Signals mastery
read article
How to mock NgRx Signal Stores for unit tests and Storybook Play interaction tests (both manually and automatically)
read article
Derivations in Reactivity
read article
Improve data service connectivity in Signal Stores using the withDataService Custom Store Feature
read article
How Signals Can Boost Your Angular Performance
read article
Featured ones: