Async provider refactoring
All checks were successful
Lint / lint (push) Successful in 14s

This commit is contained in:
Julien Valverdé
2025-03-28 20:27:25 +01:00
parent 8ea9146dd9
commit aa46ecc82d

View File

@@ -1,4 +1,4 @@
import { Array, Context, Effect, Exit, Layer, Ref, Runtime, Scope } from "effect" import { Array, Context, Effect, ExecutionStrategy, Exit, Layer, Ref, Runtime, Scope } from "effect"
import * as React from "react" import * as React from "react"
import * as ReffuseRuntime from "./ReffuseRuntime.js" import * as ReffuseRuntime from "./ReffuseRuntime.js"
@@ -76,6 +76,10 @@ const makeProvider = <R>(Context: React.Context<Context.Context<R>>): ReactProvi
export type AsyncReactProvider<R> = React.FC<{ export type AsyncReactProvider<R> = React.FC<{
readonly layer: Layer.Layer<R, unknown> readonly layer: Layer.Layer<R, unknown>
readonly options?: {
readonly scope?: Scope.Scope
readonly finalizerExecutionStrategy?: ExecutionStrategy.ExecutionStrategy
}
readonly fallback?: React.ReactNode readonly fallback?: React.ReactNode
readonly children?: React.ReactNode readonly children?: React.ReactNode
}> }>
@@ -93,11 +97,33 @@ const makeAsyncProvider = <R>(Context: React.Context<Context.Context<R>>): Async
return function ReffuseContextAsyncReactProvider(props) { return function ReffuseContextAsyncReactProvider(props) {
const runtime = ReffuseRuntime.useRuntime() const runtime = ReffuseRuntime.useRuntime()
const runSync = React.useMemo(() => Runtime.runSync(runtime), [runtime])
const runFork = React.useMemo(() => Runtime.runFork(runtime), [runtime])
const [promise, setPromise] = React.useState(Promise.withResolvers<Context.Context<R>>().promise)
React.useEffect(() => {
const { promise, resolve, reject } = Promise.withResolvers<Context.Context<R>>()
setPromise(promise)
const scope = runSync(props.options?.scope
? Scope.fork(props.options.scope, props.options?.finalizerExecutionStrategy ?? ExecutionStrategy.sequential)
: Scope.make(props.options?.finalizerExecutionStrategy)
)
Effect.context<R>().pipe(
Effect.match({
onSuccess: resolve,
onFailure: reject,
}),
const promise = React.useMemo(() => Effect.context<R>().pipe(
Effect.provide(props.layer), Effect.provide(props.layer),
Runtime.runPromise(runtime), Effect.provideService(Scope.Scope, scope),
), [props.layer, runtime]) effect => runFork(effect, { ...props.options, scope }),
)
return () => { runFork(Scope.close(scope, Exit.void)) }
}, [props.layer, runSync, runFork])
return React.createElement(React.Suspense, { return React.createElement(React.Suspense, {
children: React.createElement(ReffuseContextAsyncReactProviderInner, { ...props, promise }), children: React.createElement(ReffuseContextAsyncReactProviderInner, { ...props, promise }),