0.1.11 #14
@@ -1,4 +1,4 @@
|
|||||||
import { Array, Context, Effect, ExecutionStrategy, Exit, Layer, Ref, Runtime, Scope } from "effect"
|
import { Array, Context, Effect, ExecutionStrategy, Exit, Layer, Match, Ref, Runtime, Scope } from "effect"
|
||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
import * as ReffuseRuntime from "./ReffuseRuntime.js"
|
import * as ReffuseRuntime from "./ReffuseRuntime.js"
|
||||||
|
|
||||||
@@ -25,6 +25,8 @@ export type R<T> = T extends ReffuseContext<infer R> ? R : never
|
|||||||
export type ReactProvider<R> = React.FC<{
|
export type ReactProvider<R> = React.FC<{
|
||||||
readonly layer: Layer.Layer<R, unknown, Scope.Scope>
|
readonly layer: Layer.Layer<R, unknown, Scope.Scope>
|
||||||
readonly scope?: Scope.Scope
|
readonly scope?: Scope.Scope
|
||||||
|
readonly finalizerExecutionStrategy?: ExecutionStrategy.ExecutionStrategy
|
||||||
|
readonly finalizerExecutionMode?: "sync" | "fork"
|
||||||
readonly children?: React.ReactNode
|
readonly children?: React.ReactNode
|
||||||
}>
|
}>
|
||||||
|
|
||||||
@@ -32,16 +34,25 @@ const makeProvider = <R>(Context: React.Context<Context.Context<R>>): ReactProvi
|
|||||||
return function ReffuseContextReactProvider(props) {
|
return function ReffuseContextReactProvider(props) {
|
||||||
const runtime = ReffuseRuntime.useRuntime()
|
const runtime = ReffuseRuntime.useRuntime()
|
||||||
const runSync = React.useMemo(() => Runtime.runSync(runtime), [runtime])
|
const runSync = React.useMemo(() => Runtime.runSync(runtime), [runtime])
|
||||||
|
const runFork = React.useMemo(() => Runtime.runFork(runtime), [runtime])
|
||||||
|
|
||||||
const makeScope = React.useMemo(() => props.scope
|
const makeScope = React.useMemo(() => props.scope
|
||||||
? Scope.fork(props.scope, ExecutionStrategy.sequential)
|
? Scope.fork(props.scope, props.finalizerExecutionStrategy ?? ExecutionStrategy.sequential)
|
||||||
: Scope.make(),
|
: Scope.make(props.finalizerExecutionStrategy ?? ExecutionStrategy.sequential),
|
||||||
[props.scope])
|
[props.scope])
|
||||||
|
|
||||||
const makeContext = React.useCallback((scope: Scope.CloseableScope) => Effect.context<R>().pipe(
|
const makeContext = (scope: Scope.CloseableScope) => Effect.context<R>().pipe(
|
||||||
Effect.provide(props.layer),
|
Effect.provide(props.layer),
|
||||||
Effect.provideService(Scope.Scope, scope),
|
Effect.provideService(Scope.Scope, scope),
|
||||||
), [props.layer])
|
)
|
||||||
|
|
||||||
|
const closeScope = (scope: Scope.CloseableScope) => Scope.close(scope, Exit.void).pipe(
|
||||||
|
effect => Match.value(props.finalizerExecutionMode ?? "sync").pipe(
|
||||||
|
Match.when("sync", () => { runSync(effect) }),
|
||||||
|
Match.when("fork", () => { runFork(effect) }),
|
||||||
|
Match.exhaustive,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
const [isInitialRun, initialScope, initialValue] = React.useMemo(() => Effect.Do.pipe(
|
const [isInitialRun, initialScope, initialValue] = React.useMemo(() => Effect.Do.pipe(
|
||||||
Effect.bind("isInitialRun", () => Ref.make(true)),
|
Effect.bind("isInitialRun", () => Ref.make(true)),
|
||||||
@@ -57,7 +68,7 @@ const makeProvider = <R>(Context: React.Context<Context.Context<R>>): ReactProvi
|
|||||||
Effect.if({
|
Effect.if({
|
||||||
onTrue: () => Ref.set(isInitialRun, false).pipe(
|
onTrue: () => Ref.set(isInitialRun, false).pipe(
|
||||||
Effect.map(() =>
|
Effect.map(() =>
|
||||||
() => runSync(Scope.close(initialScope, Exit.void))
|
() => closeScope(initialScope)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|
||||||
@@ -68,13 +79,13 @@ const makeProvider = <R>(Context: React.Context<Context.Context<R>>): ReactProvi
|
|||||||
Effect.sync(() => setValue(context))
|
Effect.sync(() => setValue(context))
|
||||||
),
|
),
|
||||||
Effect.map(({ scope }) =>
|
Effect.map(({ scope }) =>
|
||||||
() => runSync(Scope.close(scope, Exit.void))
|
() => closeScope(scope)
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
runSync,
|
runSync,
|
||||||
), [makeScope, makeContext, runSync])
|
), [makeScope, runSync, runFork])
|
||||||
|
|
||||||
return React.createElement(Context, { ...props, value })
|
return React.createElement(Context, { ...props, value })
|
||||||
}
|
}
|
||||||
@@ -84,6 +95,7 @@ export type AsyncReactProvider<R> = React.FC<{
|
|||||||
readonly layer: Layer.Layer<R, unknown, Scope.Scope>
|
readonly layer: Layer.Layer<R, unknown, Scope.Scope>
|
||||||
readonly scope?: Scope.Scope
|
readonly scope?: Scope.Scope
|
||||||
readonly finalizerExecutionStrategy?: ExecutionStrategy.ExecutionStrategy
|
readonly finalizerExecutionStrategy?: ExecutionStrategy.ExecutionStrategy
|
||||||
|
readonly finalizerExecutionMode?: "sync" | "fork"
|
||||||
readonly fallback?: React.ReactNode
|
readonly fallback?: React.ReactNode
|
||||||
readonly children?: React.ReactNode
|
readonly children?: React.ReactNode
|
||||||
}>
|
}>
|
||||||
@@ -112,7 +124,7 @@ const makeAsyncProvider = <R>(Context: React.Context<Context.Context<R>>): Async
|
|||||||
|
|
||||||
const scope = runSync(props.scope
|
const scope = runSync(props.scope
|
||||||
? Scope.fork(props.scope, props.finalizerExecutionStrategy ?? ExecutionStrategy.sequential)
|
? Scope.fork(props.scope, props.finalizerExecutionStrategy ?? ExecutionStrategy.sequential)
|
||||||
: Scope.make(props.finalizerExecutionStrategy)
|
: Scope.make(props.finalizerExecutionStrategy ?? ExecutionStrategy.sequential)
|
||||||
)
|
)
|
||||||
|
|
||||||
Effect.context<R>().pipe(
|
Effect.context<R>().pipe(
|
||||||
@@ -126,7 +138,13 @@ const makeAsyncProvider = <R>(Context: React.Context<Context.Context<R>>): Async
|
|||||||
effect => runFork(effect, { ...props, scope }),
|
effect => runFork(effect, { ...props, scope }),
|
||||||
)
|
)
|
||||||
|
|
||||||
return () => { runFork(Scope.close(scope, Exit.void)) }
|
return () => Scope.close(scope, Exit.void).pipe(
|
||||||
|
effect => Match.value(props.finalizerExecutionMode ?? "sync").pipe(
|
||||||
|
Match.when("sync", () => { runSync(effect) }),
|
||||||
|
Match.when("fork", () => { runFork(effect) }),
|
||||||
|
Match.exhaustive,
|
||||||
|
)
|
||||||
|
)
|
||||||
}, [props.layer, runSync, runFork])
|
}, [props.layer, runSync, runFork])
|
||||||
|
|
||||||
return React.createElement(React.Suspense, {
|
return React.createElement(React.Suspense, {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ export interface ScopeOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface UseScopeOptions extends RenderOptions, ScopeOptions {
|
export interface UseScopeOptions extends RenderOptions, ScopeOptions {
|
||||||
|
readonly scope?: Scope.Scope
|
||||||
readonly finalizerExecutionMode?: "sync" | "fork"
|
readonly finalizerExecutionMode?: "sync" | "fork"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,10 +102,23 @@ export abstract class ReffuseNamespace<R> {
|
|||||||
const runSync = this.useRunSync()
|
const runSync = this.useRunSync()
|
||||||
const runFork = this.useRunFork()
|
const runFork = this.useRunFork()
|
||||||
|
|
||||||
|
const makeScope = React.useMemo(() => options?.scope
|
||||||
|
? Scope.fork(options.scope, options.finalizerExecutionStrategy ?? ExecutionStrategy.sequential)
|
||||||
|
: Scope.make(options?.finalizerExecutionStrategy ?? ExecutionStrategy.sequential),
|
||||||
|
[options?.scope])
|
||||||
|
|
||||||
|
const closeScope = (scope: Scope.CloseableScope) => Scope.close(scope, Exit.void).pipe(
|
||||||
|
effect => Match.value(options?.finalizerExecutionMode ?? "sync").pipe(
|
||||||
|
Match.when("sync", () => { runSync(effect) }),
|
||||||
|
Match.when("fork", () => { runFork(effect) }),
|
||||||
|
Match.exhaustive,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
const [isInitialRun, initialScope] = React.useMemo(() => runSync(Effect.all([
|
const [isInitialRun, initialScope] = React.useMemo(() => runSync(Effect.all([
|
||||||
Ref.make(true),
|
Ref.make(true),
|
||||||
Scope.make(options?.finalizerExecutionStrategy ?? ExecutionStrategy.sequential),
|
makeScope,
|
||||||
])), [])
|
])), [makeScope])
|
||||||
|
|
||||||
const [scope, setScope] = React.useState(initialScope)
|
const [scope, setScope] = React.useState(initialScope)
|
||||||
|
|
||||||
@@ -112,29 +126,18 @@ export abstract class ReffuseNamespace<R> {
|
|||||||
Effect.if({
|
Effect.if({
|
||||||
onTrue: () => Effect.as(
|
onTrue: () => Effect.as(
|
||||||
Ref.set(isInitialRun, false),
|
Ref.set(isInitialRun, false),
|
||||||
() => Scope.close(initialScope, Exit.void).pipe(
|
() => closeScope(initialScope),
|
||||||
effect => Match.value(options?.finalizerExecutionMode ?? "sync").pipe(
|
|
||||||
Match.when("sync", () => { runSync(effect) }),
|
|
||||||
Match.when("fork", () => { runFork(effect) }),
|
|
||||||
Match.exhaustive,
|
|
||||||
)
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
|
||||||
onFalse: () => Scope.make(options?.finalizerExecutionStrategy).pipe(
|
onFalse: () => makeScope.pipe(
|
||||||
Effect.tap(v => Effect.sync(() => setScope(v))),
|
Effect.tap(v => Effect.sync(() => setScope(v))),
|
||||||
Effect.map(v => () => Scope.close(v, Exit.void).pipe(
|
Effect.map(v => () => closeScope(v)),
|
||||||
effect => Match.value(options?.finalizerExecutionMode ?? "sync").pipe(
|
|
||||||
Match.when("sync", () => { runSync(effect) }),
|
|
||||||
Match.when("fork", () => { runFork(effect) }),
|
|
||||||
Match.exhaustive,
|
|
||||||
)
|
|
||||||
)),
|
|
||||||
),
|
),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
runSync,
|
runSync,
|
||||||
), [
|
), [
|
||||||
|
makeScope,
|
||||||
...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runSync, runFork],
|
...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runSync, runFork],
|
||||||
...deps,
|
...deps,
|
||||||
])
|
])
|
||||||
|
|||||||
Reference in New Issue
Block a user