Skip to content

Commit

Permalink
signal effects can be unsubscribed
Browse files Browse the repository at this point in the history
  • Loading branch information
aidlran committed Jan 21, 2024
1 parent a06ff8f commit 07526bf
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 6 deletions.
25 changes: 19 additions & 6 deletions src/signal/function/create-signal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,50 @@ import { queueUniqueMicrotask } from '../../microtask/function/queue-unique-micr
import type { Subscriber, WritableSignal } from '../types.js';

let effectListener: (() => void) | undefined;
let effectUnsubscribeSet: Set<() => void> | undefined;

export function createEffect(callback: () => void) {
effectListener = callback;
effectUnsubscribeSet = new Set();
callback();
effectListener = undefined;
const unsubscribe = function (this: Set<() => void>) {
this.forEach((fn) => fn());
}.bind(effectUnsubscribeSet);
effectListener = effectUnsubscribeSet = undefined;
return unsubscribe;
}

export function createSignal<T>(initialValue: T): WritableSignal<T> {
let currentValue = initialValue;
const subscribers = new Set<Subscriber<T>>();
const subscribers = new Set<Subscriber<T> | (() => void)>();

function unsubscribe(this: Subscriber<T> | (() => void)) {
subscribers.delete(this);
}

function signal() {
effectListener && subscribers.add(effectListener);
if (effectListener) {
subscribers.add(effectListener);
effectUnsubscribeSet!.add(unsubscribe.bind(effectListener));
}
return currentValue;
}

function push() {
subscribers.forEach((subscriber) => subscriber(currentValue));
}

signal.set = function (newValue: T) {
signal.set = (newValue: T) => {
currentValue = newValue;
// TODO: to make even more efficient: notify computed stores first,
// have them calculate, then notify all subscribers in one pass
queueUniqueMicrotask(push);
};

signal.subscribe = function (subscriber: Subscriber<T>) {
signal.subscribe = (subscriber: Subscriber<T>) => {
subscribers.add(subscriber);
subscriber(currentValue);
return () => subscribers.delete(subscriber);
return unsubscribe.bind(subscriber);
};

return signal;
Expand Down
1 change: 1 addition & 0 deletions src/signal/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export type Subscriber<T> = (newValue: T) => unknown;

export interface ReadableSignal<T> {
(): T;
/** @deprecated Use `createEffect` */
subscribe: (subscriber: Subscriber<T>) => () => void;
}

Expand Down

0 comments on commit 07526bf

Please sign in to comment.