rexfect
v0.3.0
Published
Minimal reactive state management with atoms, effects, and actions
Maintainers
Readme
Install
npm install rexfectThe Basics
import { atom, effect } from "rexfect";
// Create reactive state
const [count, setCount] = atom(0);
// React to changes
effect(() => console.log("Count:", count()));
// Update state → effect re-runs
setCount(1); // → "Count: 1"
setCount((c) => c + 1); // → "Count: 2"With React
import { atom, rx } from "rexfect/react";
const [count, setCount] = atom(0);
const Counter = () => (
<button onClick={() => setCount((c) => c + 1)}>{rx(count)}</button>
);rx(signal)— Subscribe to signal changes, re-render component only when value changes- Atoms live outside components — no Context, no Provider
- Works with React 18+ and StrictMode
Three Primitives
| Primitive | Purpose | Example |
| ---------- | ---------------- | -------------------------------------------- |
| atom() | Reactive state | const [user, setUser] = atom(null) |
| effect() | Sync reactions | effect(() => console.log(user())) |
| action() | Async operations | const login = action(async (creds) => ...) |
Key Features
- Conditional Reactivity — Dependencies tracked dynamically
- Fine-grained Updates —
pick()for property-level subscriptions - First-class Async — Actions with cancellation via
abortable() - React Suspense — Built-in
read()andloadable() - Full TypeScript — Complete inference, no manual types
- Tiny Bundle — ~3KB gzipped
Quick Examples
Async with cancellation:
import { abortable } from "rexfect/async";
const search = abortable(async ({ signal, abortPrev }, query) => {
abortPrev(); // Cancel previous
return fetch(`/api/search?q=${query}`, { signal }).then((r) => r.json());
});Store pattern:
import { atom, define } from "rexfect";
export const counterStore = define(() => {
const [count, setCount] = atom(0);
return {
count,
increment: () => setCount((c) => c + 1),
};
});Fine-grained subscriptions:
effect(() => {
const name = pick(() => user().name); // Only tracks .name
console.log(name);
});
setUser({ ...user(), visits: 100 }); // Effect does NOT runAPI at a Glance
// Core
atom(value, options?) → [Signal, Setter]
computed(fn, options?) → [ComputedSignal, refresh]
effect(fn, options?) → dispose
watch(fn, callback) → dispose
action(handler?, options?) → Action
// Utilities
batch(fn) → result
untrack(fn) → result
pick(fn, equals?) → value
selector(fn, equals?) → memoized fn
define(factory) → lazy singleton
// Async (rexfect/async)
loadable(signal) → { loading, data, error }
read(signal) → value (suspends)
wait(promise) → Promise
abortable(handler) → cancellable fn
// React (rexfect/react) - re-exports all from rexfect
rx(signal) → reactive value📚 Full Documentation
For comprehensive documentation, guides, and examples:
Includes:
- Core concepts & mental model
- Complete API reference
- React integration guide
- Async patterns & cancellation
- Best practices & common mistakes
- TypeScript guide
- Advanced patterns
