Skip to content

Instantly share code, notes, and snippets.

@oriSomething
Last active August 22, 2026 14:20
Show Gist options
  • Select an option

  • Save oriSomething/4986763accdde16f2e51999b94817f6e to your computer and use it in GitHub Desktop.

Select an option

Save oriSomething/4986763accdde16f2e51999b94817f6e to your computer and use it in GitHub Desktop.
React Service Sketch
import { signal, computed } from "@preact/signals-core";
import { inject, useServiceState } from "./service";
class WorldService {
signal = signal("world");
}
class HelloWorldService {
hello = inject(WorldService);
signal = computed(() => `hello ${this.hello.signal.value}`);
}
export function Component() {
const state = useServiceState(HelloWorldService);
return <div>{state}</div>;
}
import type { ReadonlySignal } from "@preact/signals-core";
import { createContext, use, useSyncExternalStore } from "react";
interface ServiceConstructor<T> {
new (): Service<T>;
}
interface Service<T> {
signal: ReadonlySignal<T>;
}
type ServiceRegistry = Map<ServiceConstructor<any>, Service<any>>;
let currentRegistry: ServiceRegistry | undefined;
export function inject<T>(Service: ServiceConstructor<T>): Service<T> {
return currentRegistry!.getOrInsertComputed(Service, () => new Service());
}
function getService<T>(
registry: ServiceRegistry,
Service: ServiceConstructor<T>,
): Service<T> {
const prevRegistry = currentRegistry;
currentRegistry = registry;
try {
return inject(Service);
} finally {
currentRegistry = prevRegistry;
}
}
const RegistryContext = createContext<ServiceRegistry>(new Map());
export function useServiceState<T>(ServiceConstructor: ServiceConstructor<T>): T {
const registry = use(RegistryContext);
const service = getService(registry, ServiceConstructor);
return useSyncExternalStore(service.signal.subscribe, service.signal.peek);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment