Skip to content

Instantly share code, notes, and snippets.

@AlexanderHott
Created November 9, 2024 15:31
Show Gist options
  • Save AlexanderHott/7aec3c220ba99183c67ca13a4d410e6c to your computer and use it in GitHub Desktop.
Save AlexanderHott/7aec3c220ba99183c67ca13a4d410e6c to your computer and use it in GitHub Desktop.
A typescript implementation from the "Building a Reactive Library from Scratch" blog https://dev.to/ryansolid/building-a-reactive-library-from-scratch-1i0p
type Getter<T> = () => T;
type Setter<T> = (nextValue: T) => void;
type Signal = {
execute: () => void;
dependencies: Set<Set<Signal>>;
};
const context: Signal[] = [];
function subscribe(running: Signal, subscriptions: Set<Signal>) {
subscriptions.add(running);
running.dependencies.add(subscriptions);
}
export function createSignal<T>(value: T): [Getter<T>, Setter<T>] {
const subscriptions: Set<Signal> = new Set();
const read = () => {
const running = context[context.length - 1];
if (running) subscribe(running, subscriptions);
return value;
};
const write = (nextValue: T) => {
value = nextValue;
for (const sub of [...subscriptions]) {
sub.execute();
}
};
return [read, write];
}
function cleanup(running: Signal) {
for (const dep of running.dependencies) {
dep.delete(running);
}
running.dependencies.clear();
}
export function createEffect(fn: () => void) {
let running: Signal;
const execute = () => {
cleanup(running);
context.push(running);
try {
fn();
} finally {
context.pop();
}
};
running = {
execute,
dependencies: new Set(),
};
execute();
}
export function createMemo<T>(fn: () => T) {
const [s, setS] = createSignal<T>(null as unknown as T);
createEffect(() => setS(fn()));
return s;
}
console.log("1. Create");
const [firstName, setFirstName] = createSignal("John");
const [lastName, setLastName] = createSignal("Smith");
const [showFullName, setShowFullName] = createSignal(true);
const displayName = createMemo(() => {
if (!showFullName()) return firstName();
return `${firstName()} ${lastName()}`;
});
createEffect(() => console.log("My name is", displayName()));
console.log("2. Set showFullName: false ");
setShowFullName(false);
console.log("3. Change lastName");
setLastName("Legend");
console.log("4. Set showFullName: true");
setShowFullName(true);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment