From b440503e50f402a462b2177e06c30873377c34ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Thu, 26 Jun 2025 02:55:20 +0200 Subject: [PATCH] Hook work --- .../effect-components/src/ReactComponent.ts | 4 ++ packages/effect-components/src/hooks.ts | 69 ++++++++++++++++--- 2 files changed, 62 insertions(+), 11 deletions(-) diff --git a/packages/effect-components/src/ReactComponent.ts b/packages/effect-components/src/ReactComponent.ts index c321fb7..af24644 100644 --- a/packages/effect-components/src/ReactComponent.ts +++ b/packages/effect-components/src/ReactComponent.ts @@ -33,3 +33,7 @@ export const createElement = ( ...children, ), ) + +export const useScope: Effect.Effect = Effect.gen(function*() { + +}) diff --git a/packages/effect-components/src/hooks.ts b/packages/effect-components/src/hooks.ts index 4179ba0..960bc1f 100644 --- a/packages/effect-components/src/hooks.ts +++ b/packages/effect-components/src/hooks.ts @@ -1,4 +1,4 @@ -import { Effect, type ExecutionStrategy, Runtime, Scope } from "effect" +import { Effect, ExecutionStrategy, Runtime, Scope } from "effect" import * as React from "react" @@ -8,42 +8,89 @@ export interface ScopeOptions { } -export const useScope: Effect.Effect = Effect.gen(function*() { - +export const useMemo: { + ( + factory: () => Effect.Effect, + deps: React.DependencyList, + ): Effect.Effect +} = Effect.fnUntraced(function* useMemo( + factory: () => Effect.Effect, + deps: React.DependencyList, +) { + const runtime = yield* Effect.runtime() + return React.useMemo(() => Runtime.runSync(runtime)(factory()), deps) }) -export const useEffect = ( +export const useOnce: { + (factory: () => Effect.Effect): Effect.Effect +} = Effect.fnUntraced(function* useOnce( + factory: () => Effect.Effect +) { + return yield* useMemo(factory, []) +}) + +export const useEffect: { + ( + effect: () => Effect.Effect, + deps?: React.DependencyList, + options?: ScopeOptions, + ): Effect.Effect +} = Effect.fnUntraced(function* useEffect( effect: () => Effect.Effect, deps?: React.DependencyList, options?: ScopeOptions, -): Effect.Effect => Effect.gen(function*() { +) { const runtime = yield* Effect.runtime() React.useEffect(() => { const { scope, exit } = Effect.Do.pipe( - Effect.bind("scope", () => Scope.make(options?.finalizerExecutionStrategy)), + Effect.bind("scope", () => Scope.make(options?.finalizerExecutionStrategy ?? ExecutionStrategy.sequential)), Effect.bind("exit", ({ scope }) => Effect.exit(Effect.provideService(effect(), Scope.Scope, scope))), Runtime.runSync(runtime), ) - return () => { Runtime.runSync(runtime)(Scope.close(scope, exit)) } + return () => { + switch (options?.finalizerExecutionMode ?? "sync") { + case "sync": + Runtime.runSync(runtime)(Scope.close(scope, exit)) + break + case "fork": + Runtime.runFork(runtime)(Scope.close(scope, exit)) + break + } + } }, deps) }) -export const useLayoutEffect = ( +export const useLayoutEffect: { + ( + effect: () => Effect.Effect, + deps?: React.DependencyList, + options?: ScopeOptions, + ): Effect.Effect +} = Effect.fnUntraced(function* useLayoutEffect( effect: () => Effect.Effect, deps?: React.DependencyList, options?: ScopeOptions, -): Effect.Effect => Effect.gen(function*() { +) { const runtime = yield* Effect.runtime() React.useLayoutEffect(() => { const { scope, exit } = Effect.Do.pipe( - Effect.bind("scope", () => Scope.make(options?.finalizerExecutionStrategy)), + Effect.bind("scope", () => Scope.make(options?.finalizerExecutionStrategy ?? ExecutionStrategy.sequential)), Effect.bind("exit", ({ scope }) => Effect.exit(Effect.provideService(effect(), Scope.Scope, scope))), Runtime.runSync(runtime), ) - return () => { Runtime.runSync(runtime)(Scope.close(scope, exit)) } + return () => { + switch (options?.finalizerExecutionMode ?? "sync") { + case "sync": + Runtime.runSync(runtime)(Scope.close(scope, exit)) + break + case "fork": + Runtime.runFork(runtime)(Scope.close(scope, exit)) + break + } + } }, deps) })