From 693c7b2db887b3f6647e8c77f5afe7f5eb43d9e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Wed, 26 Feb 2025 13:40:52 +0100 Subject: [PATCH] Reffuse context refactoring --- packages/reffuse/src/ReffuseContext.tsx | 88 ++++++++++++++++++------- 1 file changed, 63 insertions(+), 25 deletions(-) diff --git a/packages/reffuse/src/ReffuseContext.tsx b/packages/reffuse/src/ReffuseContext.tsx index e7e723a..f1898ff 100644 --- a/packages/reffuse/src/ReffuseContext.tsx +++ b/packages/reffuse/src/ReffuseContext.tsx @@ -4,29 +4,9 @@ import * as ReffuseRuntime from "./ReffuseRuntime.js" export class ReffuseContext { - readonly Context = React.createContext>(null!) - readonly Provider: ReffuseContextReactProvider - - constructor() { - // TODO: scope the layer creation - this.Provider = props => { - const runtime = ReffuseRuntime.useRuntime() - - const value = React.useMemo(() => Effect.context().pipe( - Effect.provide(props.layer), - Runtime.runSync(runtime), - ), [props.layer, runtime]) - - return ( - - ) - } - this.Provider.displayName = "ReffuseContextReactProvider" - } + readonly Provider = makeProvider(this.Context) + readonly AsyncProvider = makeAsyncProvider(this.Context) useContext(): Context.Context { @@ -37,15 +17,73 @@ export class ReffuseContext { const context = this.useContext() return React.useMemo(() => Layer.effectContext(Effect.succeed(context)), [context]) } - } -export type ReffuseContextReactProvider = React.FC<{ +export type R = T extends ReffuseContext ? R : never + + +export type ReactProvider = React.FC<{ readonly layer: Layer.Layer readonly children?: React.ReactNode }> -export type R = T extends ReffuseContext ? R : never +function makeProvider(Context: React.Context>): ReactProvider { + return function ReffuseContextReactProvider(props) { + const runtime = ReffuseRuntime.useRuntime() + + const value = React.useMemo(() => Effect.context().pipe( + Effect.provide(props.layer), + Runtime.runSync(runtime), + ), [props.layer, runtime]) + + return ( + + ) + } +} + +export type AsyncReactProvider = React.FC<{ + readonly layer: Layer.Layer + readonly fallback?: React.ReactNode + readonly children?: React.ReactNode +}> + +function makeAsyncProvider(Context: React.Context>): AsyncReactProvider { + function Inner({ promise, children }: { + readonly promise: Promise> + readonly children?: React.ReactNode + }) { + const value = React.use(promise) + + return ( + + ) + } + + return function ReffuseContextAsyncReactProvider(props) { + const runtime = ReffuseRuntime.useRuntime() + + const promise = React.useMemo(() => Effect.context().pipe( + Effect.provide(props.layer), + Runtime.runPromise(runtime), + ), [props.layer, runtime]) + + return ( + + + + ) + } +} export function make() {