Ultra-lightweight, selector-based state container for React. (React 18+).
No reducer. No atom graph. No proxy tracking.
Designed to stay boring, explicit, and fast.
Intent-driven architecture + deterministic mutation core.
- ⚡ Fast re-renders via fine-grained selectors
- ✍️ Explicit, imperative state mutation
- 🚫 No Provider / no Context tree
- 🧠 Framework-agnostic core (works outside React)
- 🔌 Clean integration with external logic / intent engines
- 📦 Tiny bundle, minimal runtime ~1kb gzipped (core)
(action / intent)
↓
explicit mutation
↓
single state store
↓
selector comparison (===)
↓
React re-render- No dependency graph.
- No atom system.
- No hidden proxy engine.
What you write is exactly what runs.
npm install react-fast-context-zimport { createFastContext } from "react-fast-context-z"
const counter = createFastContext({
state: { count: 0 },
actions: {
inc(s) {
s.count++
},
add(s, n: number) {
s.count += n
},
},
})
export function Counter() {
const count = counter.use(s => s.count)
return (
<button onClick={() => counter.actions.inc()}>
{count}
</button>
)
}Selectors subscribe only to what they read.
const double = counter.computed(s => s.count * 2) // outside
function View() {
const x3 = counter.computed(s => s.count * 3)
const value = double.use()
return <div>{value} + {x3.use()}</div>
}-
Selectors subscribe to the value returned by the selector.
-
Re-render happens only if the selected value changes.
watch
counter.watch(
s => s.count,
(value, prev) => {
console.log("changed:", prev, "→", value)
}
)when (one-time trigger)
counter.when(
s => s.count > 10,
(value, state) => {
console.log("threshold reached")
}
)counter.batch(() => {
counter.actions.inc()
counter.actions.add(5)
})Single notification.
try {
counter.transaction(() => {
counter.actions.add(100)
throw new Error("cancel")
})
} catch {}State automatically restored.
import { extendContext } from "react-fast-context-z"
const ctx = extendContext(counter)
const count = ctx.useValue("count")
const actions = ctx.useActions()Pure sugar API — zero magic.
react-fast-context-z allows you to control how the next state is combined with the previous one.
This is. not a deep merge system and it does not use proxy tracking.
The behavior is explicit and predictable.
const store = createFastContext({
state: { user: { name: "A", age: 20 } },
merge: "shallow", // default
})- Shallow-merge object fields
- State is shallow-merged at the top level.
- Nested objects follow normal JavaScript reference semantics.
- Ideal for mutable, intent-driven updates
set(s => {
s.user.name = "B"
})
// keeps user.age- Replace state reference entirely
- Useful when state is treated as immutable snapshots
set(() => ({
user: { name: "B", age: 30 }
}))| Mode | Use case |
|---|---|
| shallow | Explicit mutation, intent/actions, local state |
| replace | Immutable data, server snapshots, undo/redo |
- This is not deep merge.
- Arrays are replaced, not merged.
- Only top-level keys are considered.
- Re-rendering still depends purely on selector output comparison (===).
prev → merge → next → selector compare → renderimport { createIntentBus } from "intentx-core-z"
import { bindFastContext } from "react-fast-context-z"
const context = bindFastContext(counter)
const bus = createIntentBus(context)
bus.on("increment", ({ setState }) => {
setState(s => {
s.count++
})
})Designed to work cleanly with intent-first architectures.
| Criteria | react-fast-context-z | Redux | Zustand | Jotai | React Context |
|---|---|---|---|---|---|
| Provider required | ❌ | ❌ | ❌ | ❌ | ✅ |
| Selector-based render | ✅ | ✅ | ✅ | ✅ | ❌ |
| Fine-grained updates | ✅ | ✅ | ❌ | ||
| Proxy / atom graph | ❌ | ❌ | ❌ | ✅ | ❌ |
| Reducers required | ❌ | ✅ | ❌ | ❌ | ❌ |
| Direct mutation API | ✅ | ❌ | ❌ | ❌ | |
| Works outside React | ✅ | ✅ | ✅ | ❌ | ❌ |
| Intent / event-driven friendly | ✅ | ❌ | ❌ | ||
| Transaction rollback | ✅ | ❌ | ❌ | ❌ | ❌ |
| Built-in race protection | ✅ | ❌ | ❌ | ❌ | ❌ |
| Devtools ecosystem | ❌ (by design) | ✅ | ❌ | ||
| Bundle size (core) | ~1kb gzipped | larger | small | small | tiny |
react-fast-context-z focuses on:
- Explicit mutation over reducers
- Selector-driven updates without proxy tracking
- Built-in transactional safety
- Minimal runtime surface
Unlike proxy-based systems, react-fast-context-z does not track property access.
Reactivity is based purely on selector output comparison.
If your selector returns a new reference, it re-renders.
If it doesn’t, it won’t.
No magic.- already have a logic layer
- want full control over mutations
- hate hidden magic
- If you prefer immutable reducer patterns → use Redux
- If you want atom-based fine-grained graph → use Jotai
- If you want plugin-heavy ecosystem → use Zustand
--
MIT