Inspiration origin
export interface Schedule {
    schedule: () => unknown | void;
    dependencies: Set<Set<Schedule>>;
}

const context: any[] = [];

function subscribe(schedule: Schedule, subscriptions: Set<Schedule>) {
    subscriptions.add(schedule);
    schedule.dependencies.add(subscriptions);
}

export function createSignal<T>(value: T):[() => T, (val:T) =>void] {
    const subscriptions = new Set<Schedule>();

    const read = (): T => {
        const schedule = context[context.length - 1];
        if (schedule) subscribe(schedule, subscriptions);
        return value;
    };

    const write = (nextValue: T) => {
        value = nextValue;
        for (const sub of [...subscriptions]) {
            sub.schedule();
        }
    };
    return [read, write];
}

export function cleanup(reaction: any) {
    for (const dep of reaction.dependencies) {
        dep.delete(reaction);
    }
    reaction.dependencies.clear();
}

export function createReaction(schedule: () => void | unknown) {

    function track(fn: () => void) {
        cleanup(reaction);
        context.push(reaction);
        try {
            fn();
        } finally {
            context.pop();
        }
    }

    const reaction = {
        schedule,
        dependencies: new Set<Set<Schedule>>()
    }

    return { track };
}


export const autorun = (fn:() => void | unknown) => {
    const { track } = createReaction(() => {
        track(fn)
    })
    track(fn);
}
Copy the code