>()
const scope = yield* useScope(deps, options)
// biome-ignore lint/correctness/useExhaustiveDependencies: only reactive on "scope"
return yield* React.useMemo(() => Runtime.runSync(runtime)(
Effect.cached(Effect.provideService(f(), Scope.Scope, scope))
), [scope])
})
export namespace useOnMountResult {
export interface Options extends Result.forkEffectScoped.Options {
readonly equivalence?: Equivalence.Equivalence>
}
}
export const useOnMountResult: {
(
f: () => Effect.Effect>>,
options?: useOnChangeResult.Options,
): Effect.Effect, never, Result.forkEffectScoped.OutputContext>
} = Effect.fnUntraced(function* (
f: () => Effect.Effect>>,
options?: useOnChangeResult.Options,
) {
const [result, setResult] = React.useState(() => Result.initial() as Result.Result)
yield* useOnMount(() => Result.forkEffectScoped(f(), options).pipe(
Effect.andThen(Stream.fromQueue),
Stream.unwrap,
Stream.changesWith(options?.equivalence ?? Equivalence.strict()),
Stream.runForEach(result => Effect.sync(() => setResult(result))),
))
return result
})
export namespace useOnChangeResult {
export interface Options
extends useOnMountResult.Options, useReactEffect.Options {}
}
export const useOnChangeResult: {
(
f: () => Effect.Effect>>,
deps?: React.DependencyList,
options?: useOnChangeResult.Options,
): Effect.Effect<
Result.Result,
never,
Exclude, Scope.Scope>
>
} = Effect.fnUntraced(function* (
f: () => Effect.Effect>>,
deps?: React.DependencyList,
options?: useOnChangeResult.Options,
) {
const [result, setResult] = React.useState(() => Result.initial() as Result.Result)
yield* useReactEffect(() => Result.forkEffectScoped(f(), options).pipe(
Effect.andThen(Stream.fromQueue),
Stream.unwrap,
Stream.changesWith(options?.equivalence ?? Equivalence.strict()),
Stream.runForEach(result => Effect.sync(() => setResult(result))),
), deps, options)
return result
})
export namespace useReactEffect {
export interface Options {
readonly finalizerExecutionMode?: "sync" | "fork"
readonly finalizerExecutionStrategy?: ExecutionStrategy.ExecutionStrategy
}
}
export const useReactEffect: {
(
f: () => Effect.Effect,
deps?: React.DependencyList,
options?: useReactEffect.Options,
): Effect.Effect>
} = Effect.fnUntraced(function* (
f: () => Effect.Effect,
deps?: React.DependencyList,
options?: useReactEffect.Options,
) {
const runtime = yield* Effect.runtime>()
// biome-ignore lint/correctness/useExhaustiveDependencies: use of React.DependencyList
React.useEffect(() => runReactEffect(runtime, f, options), deps)
})
const runReactEffect = (
runtime: Runtime.Runtime>,
f: () => Effect.Effect,
options?: useReactEffect.Options,
) => Effect.Do.pipe(
Effect.bind("scope", () => Scope.make(options?.finalizerExecutionStrategy ?? defaultOptions.finalizerExecutionStrategy)),
Effect.bind("exit", ({ scope }) => Effect.exit(Effect.provideService(f(), Scope.Scope, scope))),
Effect.map(({ scope }) =>
() => {
switch (options?.finalizerExecutionMode ?? "fork") {
case "sync":
Runtime.runSync(runtime)(Scope.close(scope, Exit.void))
break
case "fork":
Runtime.runFork(runtime)(Scope.close(scope, Exit.void))
break
}
}
),
Runtime.runSync(runtime),
)
export namespace useReactLayoutEffect {
export type Options = useReactEffect.Options
}
export const useReactLayoutEffect: {
(
f: () => Effect.Effect,
deps?: React.DependencyList,
options?: useReactLayoutEffect.Options,
): Effect.Effect>
} = Effect.fnUntraced(function* (
f: () => Effect.Effect,
deps?: React.DependencyList,
options?: useReactLayoutEffect.Options,
) {
const runtime = yield* Effect.runtime>()
// biome-ignore lint/correctness/useExhaustiveDependencies: use of React.DependencyList
React.useLayoutEffect(() => runReactEffect(runtime, f, options), deps)
})
export const useCallbackSync: {
(
f: (...args: Args) => Effect.Effect,
deps: React.DependencyList,
): Effect.Effect<(...args: Args) => A, never, R>
} = Effect.fnUntraced(function* (
f: (...args: Args) => Effect.Effect,
deps: React.DependencyList,
) {
// biome-ignore lint/style/noNonNullAssertion: context initialization
const runtimeRef = React.useRef>(null!)
runtimeRef.current = yield* Effect.runtime()
// biome-ignore lint/correctness/useExhaustiveDependencies: use of React.DependencyList
return React.useCallback((...args: Args) => Runtime.runSync(runtimeRef.current)(f(...args)), deps)
})
export const useCallbackPromise: {
(
f: (...args: Args) => Effect.Effect,
deps: React.DependencyList,
): Effect.Effect<(...args: Args) => Promise, never, R>
} = Effect.fnUntraced(function* (
f: (...args: Args) => Effect.Effect,
deps: React.DependencyList,
) {
// biome-ignore lint/style/noNonNullAssertion: context initialization
const runtimeRef = React.useRef>(null!)
runtimeRef.current = yield* Effect.runtime()
// biome-ignore lint/correctness/useExhaustiveDependencies: use of React.DependencyList
return React.useCallback((...args: Args) => Runtime.runPromise(runtimeRef.current)(f(...args)), deps)
})
export namespace useContext {
export type Options = useOnChange.Options
}
export const useContext = (
layer: Layer.Layer,
options?: useContext.Options,
): Effect.Effect, E, RIn> => useOnChange(() => Effect.context().pipe(
Effect.map(context => ManagedRuntime.make(Layer.provide(layer, Layer.succeedContext(context)))),
Effect.tap(runtime => Effect.addFinalizer(() => runtime.disposeEffect)),
Effect.andThen(runtime => runtime.runtimeEffect),
Effect.andThen(runtime => runtime.context),
), [layer], options)