Frontend Infrastructure · Deterministic Execution

Event-Driven State & Execution Framework for React

A lightweight framework that models UI behavior as deterministic event streams, enabling lifecycle-bound execution and targeted rendering in React applications.

The project treats complex UI behavior as an execution systems problem: state changes should be explicit, ordering should be deterministic, and only subscribed components should react. These same principles map naturally onto modern AI interfaces, where token streams, tool events, and real-time updates must be coordinated predictably.
React RxJS TypeScript Event streams Deterministic execution

TL;DR

This framework models application behavior as explicit event streams rather than implicit shared state mutation. Events drive deterministic state reduction, subscriptions are bound to component lifecycle, and only mounted consumers react. The result is more predictable execution and narrower render propagation in complex UI systems.

  • Events describe what happened instead of mutating global state directly.
  • Reducers determine state evolution in a replayable, deterministic way.
  • Lifecycle-bound subscriptions ensure only mounted components react to updates.
  • Targeted rendering avoids broad re-render cascades common in context-heavy architectures.
This work is relevant to AI product engineering because modern model-driven interfaces are increasingly event-centric: streamed tokens, tool calls, partial updates, optimistic UI, and multi-step workflows all benefit from deterministic execution boundaries.

Execution Overview

The core problem was not state storage alone. It was execution order: how updates propagate, which components respond, and whether behavior remains predictable as an application becomes more interactive.

User interaction / async event │ ▼ Explicit event dispatch │ ▼ Observable stream │ ▼ Deterministic reducer pipeline │ ▼ Derived state update │ ▼ Subscribed mounted components react │ ▼ Targeted re-render
Core idea: UI behavior becomes a predictable event pipeline instead of a chain of implicit component mutations.

Origin

My earlier frontend work moved through jQuery, Angular, and then React. Angular provided structure, but often made it difficult to shape architecture outside its intended patterns. React restored flexibility, but as applications grew, state management complexity surfaced again in a different form.

The recurring problems were scattered state, implicit execution order, prop drilling, memoization layers, and difficulty understanding why a given update caused broad portions of the tree to re-render.

After experimenting with Redux, Zustand, and React Query, I revisited RxJS and began exploring a different model: express behavior as explicit event streams, then let state become the deterministic result of those events.

The Problem

Many React architectures rely on shared mutable state plus implicit propagation rules. That can be acceptable for small applications, but as complexity grows it becomes harder to reason about ordering, side effects, and render scope.

Execution ambiguity
Updates often trigger indirectly through shared state rather than explicit event flow.
Render breadth
Context or store updates can cause broad re-render cascades across unrelated components.
Lifecycle coupling
Subscriptions and async behavior can outlive components unless disposal is handled carefully.
Debuggability
Implicit update chains are difficult to replay, inspect, and reason about deterministically.

System Design

The framework separates behavior into three explicit layers so execution remains predictable.

1) Events

Events describe what occurred. They are explicit signals emitted by components or async processes rather than hidden mutations against shared state.

  • Explicit action boundary
  • Composable event sources
  • Natural fit for async workflows

2) Reducers

Reducers determine how state evolves from those events. This makes application state replayable, testable, and deterministic.

  • Predictable state transitions
  • Replay-friendly execution
  • Separation of mutation from reaction

3) Subscriptions

Subscriptions define which mounted components react to which streams, keeping updates localized instead of globally propagated.

  • Lifecycle-bound listeners
  • Scoped reactions
  • Narrower render impact

4) Execution boundary

The architecture makes update flow explicit: event emission, reduction, subscription, and render are distinct stages rather than one merged mechanism.

  • Deterministic ordering
  • Clearer mental model
  • Safer async coordination

Declaring Events

Event channels are defined explicitly and then consumed through hooks and providers.

Event declaration

const [useEvents, EventsProvider] = createEvents(rx => ({
  addToCart$: rx(),
  removeFromCart$: rx()
}));

Deterministic State Reduction

State becomes the deterministic result of event history rather than imperative mutation.

Reducer binding

const state = useReducedState(initialState, action => [
  action('addToCart$', addReducer),
  action('removeFromCart$', removeReducer)
]);
Instead of mutating shared state directly, components emit events and reducers define how those events change the application state.

Lifecycle-Bound Execution

Subscriptions are attached when components mount and disposed when they unmount, ensuring only live UI participates in execution.

Component mounts │ ▼ Subscribe to event stream │ ▼ Receive matching events │ ▼ Update derived local state │ ▼ Component unmounts │ ▼ Dispose subscription deterministically

This prevents subtle bugs where async emissions or shared listeners outlive the UI surface that originally created them.

Targeted Rendering

A key goal of the system was to reduce unnecessary render propagation by keeping reactions tied to explicit subscriptions.

Render instrumentation

function useRenderCount(name: string) {
  const count = useRef(0);
  count.current += 1;

  console.log(`${name} render #${count.current}`);
}
Observed render output

// Context-based state update

ProductList render #2
ProductCard render #2
Cart render #2
Checkout render #2


// Event-driven state update

Cart render #2

Concrete Example: Eliminating Re-render Cascades

The difference is easiest to see in a simple cart flow.

Typical context-based model

CartProvider ├─ ProductList │ ├─ ProductCard │ └─ ProductCard ├─ Cart └─ Checkout

When cart state updates, the provider boundary changes and multiple consumers can re-render even if they do not depend directly on the updated value.

Cart update → Context change ProductList re-renders ProductCard re-renders Cart re-renders Checkout re-renders

Event-driven model

addToCart$ event emitted Cart re-renders ProductList unchanged Checkout unchanged

Only the subscribed consumer reacts, which narrows render scope and makes execution behavior easier to reason about.

The value is not merely performance. It is predictability: a narrower reaction surface makes complex UI systems easier to debug and evolve.

Design Tradeoffs

Event streams vs direct mutation

Direct mutation is simpler at small scale, but event streams provide stronger guarantees around explicit behavior and execution order.

Localized subscriptions vs global stores

Localized subscriptions reduce render breadth, but require developers to model relationships in terms of events rather than direct shared access.

Reducer structure vs imperative updates

Reducers impose more structure up front, but improve replayability, predictability, and debuggability as complexity grows.

Why This Matters for AI Interfaces

Modern AI products increasingly behave like event systems rather than traditional request-response applications. Streaming tokens, tool invocations, intermediate results, conversation state changes, and optimistic UI updates all benefit from deterministic coordination.

  • Streamed model output maps naturally onto event-based rendering.
  • Tool invocation workflows benefit from explicit execution boundaries.
  • Lifecycle-bound subscriptions help prevent stale reactions in real-time interfaces.
  • Deterministic state reduction makes complex interactive flows easier to debug.
  • Targeted rendering matters when interfaces update continuously during generation.
As AI products become more interactive, frontend reliability becomes an execution problem as much as a visual one. The same deterministic systems thinking used in backend evaluation and data pipelines also applies to real-time model-driven user interfaces.