From 6c843562ab98f0ee174558a1131cec4e08f8209c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Tue, 18 Feb 2025 23:47:32 +0100 Subject: [PATCH] usePromiseScoped fork implementation --- packages/reffuse/src/Reffuse.ts | 72 ++++++++++++++++++++++++++------- 1 file changed, 57 insertions(+), 15 deletions(-) diff --git a/packages/reffuse/src/Reffuse.ts b/packages/reffuse/src/Reffuse.ts index 79dc033..6eb0753 100644 --- a/packages/reffuse/src/Reffuse.ts +++ b/packages/reffuse/src/Reffuse.ts @@ -301,38 +301,80 @@ export class Reffuse { usePromiseScoped( effect: Effect.Effect, deps?: React.DependencyList, - options?: { readonly signal?: AbortSignal } & RenderOptions & ScopeOptions, + options?: { readonly signal?: AbortSignal } & Runtime.RunForkOptions & RenderOptions & ScopeOptions, ): Promise { const runSync = this.useRunSync() - const runPromise = this.useRunPromise() + const runFork = this.useRunFork() - const [value, setValue] = React.useState(new Promise(() => {})) + const [value, setValue] = React.useState(Promise.withResolvers().promise) React.useEffect(() => { - const controller = new AbortController() - const signal = AbortSignal.any([ - controller.signal, - ...options?.signal ? [options.signal] : [], - ]) + const { promise, resolve, reject } = Promise.withResolvers() + setValue(promise) const scope = runSync(Scope.make(options?.finalizerExecutionStrategy)) - setValue(runPromise(Effect.provideService(effect, Scope.Scope, scope), { - ...options, - signal, - })) + + const fiber = effect.pipe( + Effect.provideService(Scope.Scope, scope), + Effect.match({ + onSuccess: resolve, + onFailure: reject, + }), + + // TODO: use scope from RunForkOptions? + effect => runFork(effect, options), + ) return () => { - controller.abort() - runSync(Scope.close(scope, Exit.void)) + Fiber.interrupt(fiber).pipe( + Effect.andThen(Scope.close(scope, Exit.void)), + Effect.andThen(Effect.sync(() => { reject() })), // TODO: Relevant? + runFork, + ) } }, [ - ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runSync, runPromise], + ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runSync, runFork], ...(deps ?? []), ]) return value } + // usePromiseScoped( + // effect: Effect.Effect, + // deps?: React.DependencyList, + // options?: { readonly signal?: AbortSignal } & RenderOptions & ScopeOptions, + // ): Promise { + // const runSync = this.useRunSync() + // const runPromise = this.useRunPromise() + + // const [value, setValue] = React.useState(new Promise(() => {})) + + // React.useEffect(() => { + // const controller = new AbortController() + // const signal = AbortSignal.any([ + // controller.signal, + // ...options?.signal ? [options.signal] : [], + // ]) + + // const scope = runSync(Scope.make(options?.finalizerExecutionStrategy)) + // setValue(runPromise(Effect.provideService(effect, Scope.Scope, scope), { + // ...options, + // signal, + // })) + + // return () => { + // controller.abort() + // runSync(Scope.close(scope, Exit.void)) + // } + // }, [ + // ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runSync, runPromise], + // ...(deps ?? []), + // ]) + + // return value + // } + useRef(value: A): SubscriptionRef.SubscriptionRef { return this.useMemo(