react-contextless
v1.0.0
Published
A backend-style runtime for React with middleware, DI, plugins, and structured action execution.
Maintainers
Keywords
Readme
⚡ react-contextless
🚀 A reactive service runtime for React applications.
Build scalable frontend systems using reactive services, computed state, batching, and runtime orchestration — without Context providers or reducer boilerplate.
What is react-contextless?
react-contextless is a lightweight runtime framework for React applications.
It combines:
- reactive services
- service containers
- batching
- computed state
- runtime orchestration
- selector-based subscriptions
into a single runtime layer.
Unlike traditional React state libraries, it focuses on:
- service-oriented architecture
- explicit runtime orchestration
- external reactive systems
- framework-agnostic business logic
Why react-contextless?
Modern frontend applications often suffer from:
business logic inside components
- prop drilling
- provider nesting
- duplicated async state handling
- inconsistent orchestration
- tightly coupled UI state
react-contextless solves this by introducing a runtime execution layer:
- services hold business logic
- React becomes a rendering adapter
- state lives outside component trees
- orchestration becomes explicit
- services communicate through reactive runtime updates
Features
- ⚡ Reactive service architecture
- 🧠 Service container runtime
- 🚫 No Context provider required
- ⚛️ React 18 useSyncExternalStore
- 🔥 Batched reactive updates
- 🧩 Computed / derived state
- 🌐 Cross-service reactivity
- 📦 Singleton service runtime
- 🔌 Async factory injection
- 🛡 Stable concurrent rendering
- 🧱 Framework-agnostic core
- ✨ Tiny runtime footprint
Mental Model
UI
↓
useService()
↓
React Bridge
↓
Reactive Runtime
↓
Services
↓
Service Container
↓
Business LogicInstallation
npm install react-contextlessQuick Example
Create Tokens
// tokens.ts
import { createToken } from 'react-contextless'
import type { ApiService } from './services/api'
import type { AuthService } from './services/auth'
export const ApiToken = createToken<ApiService>('ApiService')
export const AuthToken = createToken<AuthService>('AuthService')
Create Services
Api Service
// services/api.ts
export class ApiService {
async getUser() {
return { id: '1', name: 'Tung' }
}
}Auth Service
// services/auth.ts
import { ReactiveService } from 'react-contextless'
import { ApiToken } from '../tokens'
import type { ApiService } from './api'
export class AuthService extends ReactiveService {
static inject = [ApiToken]
user: any = null
constructor(private api: ApiService) {
super()
}
async login() {
this.user = await this.api.getUser()
this.emit()
}
logout() {
this.user = null
this.emit()
}
}Create App Runtime
// app.ts
import { createApp } from 'react-contextless'
import { ApiToken, AuthToken } from './tokens'
import { ApiService } from './services/api'
import { AuthService } from './services/auth'
export const app = createApp([
{ token: ApiToken, useClass: ApiService },
{ token: AuthToken, useClass: AuthService },
])Create React Bridge
// runtime.ts
import { createBridge } from 'react-contextless'
import { app } from './app'
export const useService = createBridge(app)React Usage
// App.tsx
import { useService } from './runtime'
import { AuthToken } from './tokens'
export function App() {
const auth = useService(AuthToken)
return (
<div>
<button onClick={() => auth.login()}>Login</button>
<pre>{JSON.stringify(auth.user, null, 2)}</pre>
</div>
)
}Service Dependencies
Services can depend on other services
export class AuthService {
static inject = [ApiToken]
constructor(private api: ApiService) {}
}Async Factory Injection
const app = createApp([
{
token: ApiToken,
async useFactory() {
const api = await createApi()
return api
},
},
])Reactive Services
Reactive services automatically notify React subscribers:
import { ReactiveService } from 'react-contextless'
export class CounterService extends ReactiveService {
count = 0
increment() {
this.count++
this.emit()
}
}useService
const counter = useService(CounterToken)Selector Subscriptions
Subscribe only to specific values:
const count = useService(CounterToken, (s) => s.count)
// Re-render occurs only if the selected value changesRe-render occurs only if the selected value changes.
Computed State
Derived reactive state:
import { createComputed } from 'react-contextless'
const fullName = createComputed(
() => `${user.first} ${user.last}`,
[userService]
)Cross-Service Reactivity
Services can react to other services:
export class ProfileService {
profile: any
constructor(auth: AuthService) {
const computed = createComputed(
() => ({ name: auth.user?.name ?? 'Guest' }),
[auth]
)
this.profile = computed.get
}
}Batching
Multiple updates are batched automatically:
counter.increment()
counter.increment()
counter.increment()Single render tick
Scoped Containers
Create isolated runtime scopes:
const scope = app.createScope()Useful for:
- route-level isolation
- modal runtime state
- micro-frontends
- sandbox execution
Runtime Architecture
Services
↓
Reactive Runtime
↓
Batch Scheduler
↓
React Bridge
↓
UIFull Example
import React from 'react'
import {
createApp,
createBridge,
createToken,
ReactiveService,
} from 'react-contextless'
class CounterService
extends ReactiveService
{
count = 0
increment() {
this.count++
this.emit()
}
}
const CounterToken =
createToken<CounterService>(
'CounterService',
)
const app = createApp([
{
token: CounterToken,
useClass: CounterService,
},
])
const useService =
createBridge(app)
export function App() {
const counter =
useService(
CounterToken,
(s) => s.count,
)
const service =
useService(CounterToken)
return (
<button
onClick={() => {
service.increment()
}}
>
Count: {counter}
</button>
)
}Comparison
| Criteria | react-contextless. | React Context | Zustand | Redux | | -------------------------- | ----------------------| ------------- | ------- | ------ | | No Provider | ✅ | ❌ | ✅ | ❌ | | Service Container | ✅ | ❌ | ❌ | ❌ | | Reactive Services | ✅ | ❌ | ⚠️ | ❌ | | Computed State | ✅ | ⚠️ | ⚠️ | ❌ | | Batch Runtime | ✅ | ❌ | ⚠️ | ⚠️ | | Cross-Service Reactivity | ✅ | ❌ | ❌ | ❌ | | Selector Rendering | ✅ | ❌ | ✅ | ✅ | | Backend-style Architecture | ✅ | ❌ | ❌ | ⚠️ | | External Runtime Logic | ✅ | ❌ | ⚠️ | ⚠️ |
Core Concepts
Services contain business logic and runtime state.
class AuthService extends ReactiveService {}Design Principles
- Explicit runtime execution
- Service-oriented frontend architecture
- Composition over inheritance
- Deterministic reactive updates
- Minimal runtime abstraction
- Framework-agnostic business layer
When to Use
- Large React applications
- Complex frontend architectures
- Service-oriented frontend systems
- Runtime orchestration
- Plugin-driven applications
- Shared business logic layers
- Backend/frontend architecture alignment
When NOT to Use
- Tiny local component state
- Simple forms
- Minimal UI prototypes
- Reducer-first immutable architectures
Publish
export {
createApp,
createToken,
ReactiveService,
createBridge,
createComputed,
batch,
}License
MIT
