0.1.0 #1
@@ -1,5 +1,6 @@
|
||||
import { Context, Effect, Fiber, FiberRefs, Layer, ManagedRuntime, Ref, Runtime, RuntimeFlags, Scope, Stream, SubscriptionRef } from "effect"
|
||||
import { Context, Effect, Fiber, Layer, ManagedRuntime, Ref, Runtime, Scope, Stream, SubscriptionRef } from "effect"
|
||||
import React from "react"
|
||||
import * as ReffuseReactContext from "./ReffuseReactContext.js"
|
||||
|
||||
|
||||
export interface ProviderProps<R, E> {
|
||||
@@ -10,31 +11,71 @@ export interface ProviderProps<R, E> {
|
||||
|
||||
export class Reffuse<R> {
|
||||
|
||||
readonly Context = React.createContext<Runtime.Runtime<R>>(null!)
|
||||
readonly Provider: React.FC<ProviderProps<R, any>>
|
||||
readonly Context = React.createContext<ReffuseReactContext.ReffuseReactContext<R>>(null!)
|
||||
readonly Provider: React.FC<ProviderProps<R, unknown>>
|
||||
|
||||
constructor(
|
||||
runtime: Runtime.Runtime<R>
|
||||
) {
|
||||
this.Provider = (props: ProviderProps<R, any>) => {
|
||||
const runtime = React.useMemo(() => Runtime.make({
|
||||
context: Context.empty(),
|
||||
runtimeFlags: RuntimeFlags.make(),
|
||||
fiberRefs: FiberRefs.empty(),
|
||||
}), [])
|
||||
this.Provider = (props: ProviderProps<R, unknown>) => {
|
||||
const value = React.useMemo(() => ({
|
||||
runtime,
|
||||
context: Effect.context<R>().pipe(
|
||||
Effect.provide(props.layer),
|
||||
Runtime.runSync(runtime),
|
||||
),
|
||||
}), [props.layer])
|
||||
|
||||
return (
|
||||
<this.Context
|
||||
{...props}
|
||||
value={runtime}
|
||||
value={value}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
useRuntime(): Runtime.Runtime<R> {
|
||||
return React.useContext(this.Context)
|
||||
useRuntime(): Runtime.Runtime<never> {
|
||||
return React.useContext(this.Context).runtime
|
||||
}
|
||||
|
||||
useContext(): Context.Context<R> {
|
||||
return React.useContext(this.Context).context
|
||||
}
|
||||
|
||||
|
||||
useRunSync() {
|
||||
const { runtime, context } = React.useContext(this.Context)
|
||||
|
||||
return React.useCallback(<A, E>(effect: Effect.Effect<A, E, R>): A => effect.pipe(
|
||||
Effect.provide(context),
|
||||
Runtime.runSync(runtime),
|
||||
), [runtime, context])
|
||||
}
|
||||
|
||||
useRunPromise() {
|
||||
const { runtime, context } = React.useContext(this.Context)
|
||||
|
||||
return React.useCallback(<A, E>(
|
||||
effect: Effect.Effect<A, E, R>,
|
||||
options?: { readonly signal?: AbortSignal },
|
||||
): Promise<A> => effect.pipe(
|
||||
Effect.provide(context),
|
||||
effect => Runtime.runPromise(runtime)(effect, options),
|
||||
), [runtime, context])
|
||||
}
|
||||
|
||||
useRunFork() {
|
||||
const { runtime, context } = React.useContext(this.Context)
|
||||
|
||||
return React.useCallback(<A, E>(
|
||||
effect: Effect.Effect<A, E, R>,
|
||||
options?: Runtime.RunForkOptions,
|
||||
): Fiber.RuntimeFiber<A, E> => effect.pipe(
|
||||
Effect.provide(context),
|
||||
effect => Runtime.runFork(runtime)(effect, options),
|
||||
), [runtime, context])
|
||||
}
|
||||
|
||||
|
||||
@@ -43,32 +84,32 @@ export class Reffuse<R> {
|
||||
deps?: React.DependencyList,
|
||||
options?: Runtime.RunForkOptions,
|
||||
): void {
|
||||
const runtime = this.useRuntime()
|
||||
const runFork = this.useRunFork()
|
||||
|
||||
return React.useEffect(() => {
|
||||
const fiber = runtime.runFork(Effect.scoped(self), options)
|
||||
return () => { runtime.runFork(Fiber.interrupt(fiber)) }
|
||||
}, [runtime, ...deps ?? []])
|
||||
const fiber = runFork(Effect.scoped(self), options)
|
||||
return () => { runFork(Fiber.interrupt(fiber)) }
|
||||
}, [runFork, ...deps ?? []])
|
||||
}
|
||||
|
||||
|
||||
useRef<A>(value: A): SubscriptionRef.SubscriptionRef<A> {
|
||||
const runtime = this.useRuntime()
|
||||
return React.useMemo(() => runtime.runSync(SubscriptionRef.make(value)), [])
|
||||
const runSync = this.useRunSync()
|
||||
return React.useMemo(() => runSync(SubscriptionRef.make(value)), [])
|
||||
}
|
||||
|
||||
useRefFromEffect<A, E>(effect: Effect.Effect<A, E, R>): SubscriptionRef.SubscriptionRef<A> {
|
||||
const runtime = this.useRuntime()
|
||||
const runSync = this.useRunSync()
|
||||
|
||||
return React.useMemo(() => runtime.runSync(effect.pipe(
|
||||
return React.useMemo(() => runSync(effect.pipe(
|
||||
Effect.flatMap(SubscriptionRef.make)
|
||||
)), [])
|
||||
}
|
||||
|
||||
useRefState<A>(ref: SubscriptionRef.SubscriptionRef<A>): [A, React.Dispatch<React.SetStateAction<A>>] {
|
||||
const runtime = this.useRuntime()
|
||||
const runSync = this.useRunSync()
|
||||
|
||||
const initialState = React.useMemo(() => runtime.runSync(ref), [ref])
|
||||
const initialState = React.useMemo(() => runSync(ref), [ref])
|
||||
const [reactStateValue, setReactStateValue] = React.useState(initialState)
|
||||
|
||||
this.useFork(Stream.runForEach(ref.changes, v => Effect.sync(() =>
|
||||
@@ -76,7 +117,7 @@ export class Reffuse<R> {
|
||||
)), [ref])
|
||||
|
||||
const setValue = React.useCallback((setStateAction: React.SetStateAction<A>) =>
|
||||
runtime.runSync(Ref.update(ref, previousState =>
|
||||
runSync(Ref.update(ref, previousState =>
|
||||
typeof setStateAction === "function"
|
||||
? (setStateAction as (prevState: A) => A)(previousState)
|
||||
: setStateAction
|
||||
@@ -89,5 +130,5 @@ export class Reffuse<R> {
|
||||
}
|
||||
|
||||
|
||||
export const make = <ROut, E>(layer: Layer.Layer<ROut, E, never>): Reffuse<ROut, E> =>
|
||||
export const make = <R>(): Reffuse<R> =>
|
||||
new Reffuse(ManagedRuntime.make(layer))
|
||||
|
||||
7
packages/reffuse/src/ReffuseReactContext.ts
Normal file
7
packages/reffuse/src/ReffuseReactContext.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import type { Context, Runtime } from "effect"
|
||||
|
||||
|
||||
export interface ReffuseReactContext<R> {
|
||||
readonly runtime: Runtime.Runtime<never>
|
||||
readonly context: Context.Context<R>
|
||||
}
|
||||
Reference in New Issue
Block a user