Skip to content

delpikye-v/react-fast-context

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 

Repository files navigation

⚡ react-fast-context-z

NPM Downloads

LIVE EXAMPLE


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.


Why react-fast-context-z?

  • ⚡ 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)

Mental Model

(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.


Installation

npm install react-fast-context-z

Basic Usage

import { 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 & Derived State

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.


Reactive API (Outside React)

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")
  }
)

Batch

counter.batch(() => {
  counter.actions.inc()
  counter.actions.add(5)
})

Single notification.


Transaction (Rollback Safe)

try {
  counter.transaction(() => {
    counter.actions.add(100)
    throw new Error("cancel")
  })
} catch {}

State automatically restored.


Extend Helpers (Optional Convenience)

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.


Merge Mode

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
})

Available modes

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

merge: "replace"

  • Replace state reference entirely
  • Useful when state is treated as immutable snapshots
set(() => ({
  user: { name: "B", age: 30 }
}))

When to use which?

Mode Use case
shallow Explicit mutation, intent/actions, local state
replace Immutable data, server snapshots, undo/redo

Important Notes

  • 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 → render

IntentX Integration

import { 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.


Comparison

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 ⚠️ (middleware)
Works outside React
Intent / event-driven friendly ⚠️ (action-based) ⚠️
Transaction rollback
Built-in race protection
Devtools ecosystem ❌ (by design) ⚠️ ⚠️
Bundle size (core) ~1kb gzipped larger small small tiny

⚠️ = supported but not primary design focus

react-fast-context-z focuses on:

  • Explicit mutation over reducers
  • Selector-driven updates without proxy tracking
  • Built-in transactional safety
  • Minimal runtime surface

Philosophy

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.

When to use

  • already have a logic layer
  • want full control over mutations
  • hate hidden magic

When NOT to use

  • 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

--

License

MIT

About

Ultra-lightweight, selector-based React state container. No Provider. No reducer. No proxy. No magic.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors