Skip to content

Instantly share code, notes, and snippets.

@dy
Created April 13, 2024 13:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dy/bbac687464ccf5322ab0e2fd0680dc4d to your computer and use it in GitHub Desktop.
Save dy/bbac687464ccf5322ab0e2fd0680dc4d to your computer and use it in GitHub Desktop.
signal polyfill preact
// @preact/signals compatible wrapper for signal proposal
import { Signal } from 'signal-polyfill'
const { untrack, Watcher } = Signal.subtle
export const signal = v => wrap(new Signal.State(v))
export const computed = fn => wrap(new Signal.Computed(fn))
export { untrack as untracked }
const wrap = (s) => {
let get = () => s.get()
Object.defineProperty(s, 'value', {
get,
set(v) { s.set(v) }
})
s.peek = () => untrack(get)
s.toJSON = s.then = s.toString = s.valueOf = get
return s
}
let pending = false;
let fxWatcher = new Watcher(() => {
if (!pending) {
pending = true;
queueMicrotask(flushPending);
}
});
function flushPending() {
pending = false;
console.log('flush pending')
for (const signal of fxWatcher.getPending()) {
signal.get();
}
fxWatcher.watch();
}
let idx = 0
export function effect(cb) {
let destructor;
let c = new Signal.Computed(() => { typeof destructor === 'function' && destructor(); destructor = cb(); });
c.idx = idx++
console.log('watch', c)
fxWatcher.watch(c);
c.get();
return () => {
typeof destructor === 'function' && destructor();
unwatch(c)
};
}
function unwatch(c) {
fxWatcher.unwatch(c)
}
// batched destructor (unstable) - faster
/*
let toUnwatch = new Set
function unwatch(s) {
console.log('unwatch', s)
if (!toUnwatch.size) {
queueMicrotask(flushUnwatch);
}
toUnwatch.add(s)
}
const flushUnwatch = () => {
let u = [...toUnwatch]
toUnwatch.clear()
fxWatcher.unwatch(...u)
}
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment