<div id="app"></div>
html {
font-family: sans-serif;
}
/*
* IMPLEMENTATION
*/
// global variable to store the current caller
let caller;
// simple implementation without cleanups and checks for infinite loops
function signal(initialValue) {
let _value = initialValue;
const observers = [];
return {
get value() {
if (caller && !observers.includes(caller)) {
observers.push(caller);
}
return _value;
},
set value(newValue) {
if (newValue !== _value) {
_value = newValue;
observers.forEach((fn) => fn());
}
}
};
}
function effect(fn) {
caller = fn;
fn();
caller = undefined;
}
function computed(computation) {
return {
get value() {
return computation();
}
};
}
// inspired by: https://www.thisdot.co/blog/deep-dive-into-how-signals-work-in-solidjs
/*
* USAGE
*/
const counter = signal(0);
const double = computed(() => counter.value * 2);
const button = document.createElement("button");
const paragraph = document.createElement("p");
document.body.append(button, paragraph);
button.addEventListener("click", () => counter.value++);
// these effects are hidden by the framework,
// but it's essentially what happens with signals in a component template
const updateButton = () => (button.innerText = counter.value);
effect(updateButton);
effect(() => (paragraph.innerText = double.value));
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.