Incrémental, pas une réécriture
Les composants ordinaires restent du <Component /> JSX. Un REC seulement là où il faut un service.
Le même composant tourne en SPA, sur un serveur, dans un Web Worker ou comme RSC — serveur ou client n’est qu’un détail de runtime.
MIT · React 19.2+ · Effect v4
La thèse
React et Effect ordonnancent tous deux sur des fibres. effract pilote le générateur d’un composant dans la passe de rendu de React — un seul flux de yield* pour les deux. Du React 100 % réel, sans réconciliateur remplacé.
yield* Stats un service, résolu de façon synchrone yield* hook(useState(0)) un vrai hook React, ordre stable yield* fetchUser suspend, puis reprend sur place une erreur remonte à l’error boundary la plus proche // Counter: a React component,
// written as an Effect program
const Counter = rec(function* () {
const stats = yield* Stats
const [n] = yield* hook(useState(0))
return <Row n={n} of={stats.total}/>
})
// DI checked at compile time:
createRoot(el).render(
mount(AppLive, Counter),
) Un service et un vrai hook React dans un seul corps — vérifié à la compilation.
Un composant, tous les runtimes
Layer navigateur → SPA. Layer serveur → SSR en flux. Moteur Flight → RSC. Le composant ne change jamais ; seul le runtime sous lui change.
Vite, dans le navigateur
Bun / Node en flux
hors du thread principal
Flight, en flux
Les mêmes RECs dans les quatre — démontré par les apps d’exemple.
Philosophie
Un composant React doit être presque banal — structure et interaction, rien de plus. Le difficile vit hors de React, résolu au point de composition et remis à votre JSX en résultat typé.
Retries, concurrence, cache, tracing — le travail d’Effect, hors de l’arbre de rendu, testable et réutilisable.
Plus d’états de chargement ni de hooks en cascade. Tout est résolu avant le rendu ; le corps se lit de haut en bas.
Le vrai intérêt des RSC : résoudre les dépendances à la racine de composition. effract le garde, sans le verrou.
Remisez useEffect, une lib de fetch, le context, un store, les server actions — un seul yield* couvre les trois.
Pourquoi effract
Les composants ordinaires restent du <Component /> JSX. Un REC seulement là où il faut un service.
Hooks, Suspense, error boundaries, hydratation, RSC — tout fonctionne. effract rend à travers React.
Lire un service est une lecture de Context, pas un aller-retour async. Aucun Effect.runSync au call site.
observe($ => $(count) * 2) re-rend exactement quand un atom lu change. Sans provider, sans sélecteurs.
Le même corps devient un Server Component async et émet du Flight standard.
Besoins et erreurs sont inférés depuis vos yield — mount ne compile pas sans eux.
MIT, sur npm. Commencez par la doc, ou les huit recettes de call site.