# ⚡ react-fast-context-z

[![NPM](https://img.shields.io/npm/v/react-fast-context-z.svg)](https://www.npmjs.com/package/react-fast-context-z) ![Downloads](https://img.shields.io/npm/dt/react-fast-context-z.svg)

<a href="https://codesandbox.io/p/sandbox/vvxnwp" target="_blank">LIVE EXAMPLE</a>

---

**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

```bash
(action / intent)
      ↓
explicit mutation
      ↓
single state store
      ↓
selector comparison (===)
      ↓
React re-render
```

- No dependency graph.
- No atom system.
- No hidden proxy engine.

<b>What you write is exactly what runs.</b>

---

## Installation

```bash
npm install react-fast-context-z
```

---

## Basic Usage

```ts
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**.

```ts
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)

<b>watch</b>

```ts
counter.watch(
  s => s.count,
  (value, prev) => {
    console.log("changed:", prev, "→", value)
  }
)
```

<b>when (one-time trigger)</b>

```ts
counter.when(
  s => s.count > 10,
  (value, state) => {
    console.log("threshold reached")
  }
)
```

---

## Batch

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

Single notification.

---

## Transaction (Rollback Safe)

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

State automatically restored.

---

## Extend Helpers (Optional Convenience)

```ts
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.   

```ts
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**

```ts
set(s => {
  s.user.name = "B"
})
// keeps user.age
```

#### `merge: "replace"`

- Replace state reference entirely
- Useful when state is treated as immutable snapshots

```ts
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 (===).

```bash
prev → merge → next → selector compare → render
```

---

## IntentX Integration

```ts
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

<b> react-fast-context-z focuses on:</b>
- Explicit mutation over reducers
- Selector-driven updates without proxy tracking
- Built-in transactional safety
- Minimal runtime surface

---

## Philosophy

```txt
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
