diff --git a/packages/effect-components/src/ReactComponent.ts b/packages/effect-components/src/ReactComponent.ts
index a7bf827..c321fb7 100644
--- a/packages/effect-components/src/ReactComponent.ts
+++ b/packages/effect-components/src/ReactComponent.ts
@@ -1,5 +1,5 @@
import { Effect, Runtime, type Scope } from "effect"
-import type * as React from "react"
+import * as React from "react"
export interface ReactComponent
{
@@ -8,8 +8,28 @@ export interface ReactComponent
{
export const use =
(
self: ReactComponent
,
- fn: (Component: React.FC
) => React.ReactNode
+ fn: (Component: React.FC
) => React.ReactNode,
): Effect.Effect => Effect.map(
Effect.runtime(),
runtime => fn(props => Runtime.runSync(runtime)(self(props))),
)
+
+export const useFC = (
+ self: ReactComponent
+): Effect.Effect, never, R | Scope.Scope> => Effect.map(
+ Effect.runtime(),
+ runtime => props => Runtime.runSync(runtime)(self(props)),
+)
+
+export const createElement = (
+ self: ReactComponent
,
+ props?: React.Attributes & P | null,
+ ...children: React.ReactNode[]
+): Effect.Effect => Effect.map(
+ Effect.runtime(),
+ runtime => React.createElement(
+ props => Runtime.runSync(runtime)(self(props)),
+ props,
+ ...children,
+ ),
+)
diff --git a/packages/effect-components/src/hooks.ts b/packages/effect-components/src/hooks.ts
new file mode 100644
index 0000000..4179ba0
--- /dev/null
+++ b/packages/effect-components/src/hooks.ts
@@ -0,0 +1,49 @@
+import { Effect, type ExecutionStrategy, Runtime, Scope } from "effect"
+import * as React from "react"
+
+
+export interface ScopeOptions {
+ readonly finalizerExecutionStrategy?: ExecutionStrategy.ExecutionStrategy
+ readonly finalizerExecutionMode?: "sync" | "fork"
+}
+
+
+export const useScope: Effect.Effect = Effect.gen(function*() {
+
+})
+
+export const 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("exit", ({ scope }) => Effect.exit(Effect.provideService(effect(), Scope.Scope, scope))),
+ Runtime.runSync(runtime),
+ )
+
+ return () => { Runtime.runSync(runtime)(Scope.close(scope, exit)) }
+ }, deps)
+})
+
+export const 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("exit", ({ scope }) => Effect.exit(Effect.provideService(effect(), Scope.Scope, scope))),
+ Runtime.runSync(runtime),
+ )
+
+ return () => { Runtime.runSync(runtime)(Scope.close(scope, exit)) }
+ }, deps)
+})
diff --git a/packages/effect-components/src/index.ts b/packages/effect-components/src/index.ts
index 17a9fe1..153be4b 100644
--- a/packages/effect-components/src/index.ts
+++ b/packages/effect-components/src/index.ts
@@ -1,2 +1,3 @@
+export * from "./hooks.js"
export * as ReactComponent from "./ReactComponent.js"
-export { use } from "./ReactComponent.js"
+export { use, useFC, createElement } from "./ReactComponent.js"