Hook work
All checks were successful
Lint / lint (push) Successful in 15s

This commit is contained in:
Julien Valverdé
2025-06-26 02:55:20 +02:00
parent 4088d86652
commit b440503e50
2 changed files with 62 additions and 11 deletions

View File

@@ -33,3 +33,7 @@ export const createElement = <P, E, R>(
...children, ...children,
), ),
) )
export const useScope: Effect.Effect<void> = Effect.gen(function*() {
})

View File

@@ -1,4 +1,4 @@
import { Effect, type ExecutionStrategy, Runtime, Scope } from "effect" import { Effect, ExecutionStrategy, Runtime, Scope } from "effect"
import * as React from "react" import * as React from "react"
@@ -8,42 +8,89 @@ export interface ScopeOptions {
} }
export const useScope: Effect.Effect<void> = Effect.gen(function*() { export const useMemo: {
<A, E, R>(
factory: () => Effect.Effect<A, E, R>,
deps: React.DependencyList,
): Effect.Effect<A, never, R>
} = Effect.fnUntraced(function* useMemo<A, E, R>(
factory: () => Effect.Effect<A, E, R>,
deps: React.DependencyList,
) {
const runtime = yield* Effect.runtime<R>()
return React.useMemo(() => Runtime.runSync(runtime)(factory()), deps)
}) })
export const useEffect = <E, R>( export const useOnce: {
<A, E, R>(factory: () => Effect.Effect<A, E, R>): Effect.Effect<A, never, R>
} = Effect.fnUntraced(function* useOnce<A, E, R>(
factory: () => Effect.Effect<A, E, R>
) {
return yield* useMemo(factory, [])
})
export const useEffect: {
<E, R>(
effect: () => Effect.Effect<void, E, R | Scope.Scope>,
deps?: React.DependencyList,
options?: ScopeOptions,
): Effect.Effect<void, never, R>
} = Effect.fnUntraced(function* useEffect<E, R>(
effect: () => Effect.Effect<void, E, R | Scope.Scope>, effect: () => Effect.Effect<void, E, R | Scope.Scope>,
deps?: React.DependencyList, deps?: React.DependencyList,
options?: ScopeOptions, options?: ScopeOptions,
): Effect.Effect<void, never, R> => Effect.gen(function*() { ) {
const runtime = yield* Effect.runtime<R>() const runtime = yield* Effect.runtime<R>()
React.useEffect(() => { React.useEffect(() => {
const { scope, exit } = Effect.Do.pipe( 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))), Effect.bind("exit", ({ scope }) => Effect.exit(Effect.provideService(effect(), Scope.Scope, scope))),
Runtime.runSync(runtime), 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) }, deps)
}) })
export const useLayoutEffect = <E, R>( export const useLayoutEffect: {
<E, R>(
effect: () => Effect.Effect<void, E, R | Scope.Scope>,
deps?: React.DependencyList,
options?: ScopeOptions,
): Effect.Effect<void, never, R>
} = Effect.fnUntraced(function* useLayoutEffect<E, R>(
effect: () => Effect.Effect<void, E, R | Scope.Scope>, effect: () => Effect.Effect<void, E, R | Scope.Scope>,
deps?: React.DependencyList, deps?: React.DependencyList,
options?: ScopeOptions, options?: ScopeOptions,
): Effect.Effect<void, never, R> => Effect.gen(function*() { ) {
const runtime = yield* Effect.runtime<R>() const runtime = yield* Effect.runtime<R>()
React.useLayoutEffect(() => { React.useLayoutEffect(() => {
const { scope, exit } = Effect.Do.pipe( 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))), Effect.bind("exit", ({ scope }) => Effect.exit(Effect.provideService(effect(), Scope.Scope, scope))),
Runtime.runSync(runtime), 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) }, deps)
}) })