@hyrious/utils
Utility functions I often use.
Contents
Most of the utils are quite simple, I'd suggest you to read the source code directly. Some interesting parts will be documented here.
observable(sample?)
Create a emitter that on()
returns a disposer.
let emitter = observable({ a: 1, b: "" });
let dispose = emitter.on("a", (a) => console.log(a));
emitter.emit("a", 2); // logs: 2
dispose();
To use it in typescript:
let emitter = observable<{ a: number; b: string }>();
writable(initial?)
Create a reactive value (an instance of Val
) that can be subscribed.
let count$ = writable(0);
count$.subscribe(console.log); // logs: 0
count$.set(1); // logs: 1
count$.value; // 1
To create a readonly value (i.e. no set()
), you just type-cast it to Readable
.
let count$ = writable(0);
let readonlyCount$: Readable<number> = count$;
This is super useful for using in UI frameworks.
import { useSyncExternalStore } from "use-sync-external-store/shim";
const foo$ = writable(0);
const subscribeFoo = foo$.subscribe.bind(foo$);
function App() {
const foo = useSyncExternalStore(subscribeFoo, () => foo$.value);
return <button onClick={() => foo$.set(foo$.value + 1)}>{foo}</button>;
}
Feature, not bug:
let foo$ = writable(-0);
foo$.set(+0); // won't trigger listeners because -0 === +0, same as NaN === NaN
let obj = [];
foo$.set(obj); // triggers listener(obj)
foo$.set(obj); // triggers listener(obj) again, because the object may be modified
let bar$ = writable();
bar$.subscribe(console.log); // no log, because bar$ is not ready
bar$.set(1); // logs: 1
bar$.set(undefined); // logs: undefined
batch(render)
Batch multiple calls to one to happen in next micro task.
const schedule = batch(render);
times(10, () => schedule()); // run 10 times synchronously
await tick();
expect(render).toBeCalledTimes(1); // only render once
Coding Style
1. Make sure to only export pure variables.
export let a = 1; // pure
export let a = 1 << 1; // maybe not pure (need constant folding)
export let a = {}; a.b = 1; // not pure
export function f() {} // pure
2. Correctly export isomorphic modules.
"exports": {
"./module": {
"node": "./module-node.js",
"default": "./module.js" // bundlers will be happy to see this
}
}
- No fool-proofing checks, use typescript to call attention.
License
MIT @ hyrious