import { Effect, Equivalence, Ref, type Scope, Stream, SubscriptionRef } from "effect"
import * as React from "react"
import * as Component from "./Component.js"
import * as SetStateAction from "./SetStateAction.js"
export namespace useSubscriptionRefState {
export interface Options {
readonly equivalence?: Equivalence.Equivalence
}
}
export const useSubscriptionRefState: {
(
ref: SubscriptionRef.SubscriptionRef,
options?: useSubscriptionRefState.Options>,
): Effect.Effect>], never, Scope.Scope>
} = Effect.fnUntraced(function* (
ref: SubscriptionRef.SubscriptionRef,
options?: useSubscriptionRefState.Options>,
) {
const [reactStateValue, setReactStateValue] = React.useState(yield* Component.useOnMount(() => ref))
yield* Component.useReactEffect(() => Effect.forkScoped(
Stream.runForEach(
Stream.changesWith(ref.changes, options?.equivalence ?? Equivalence.strict()),
v => Effect.sync(() => setReactStateValue(v)),
)
), [ref])
const setValue = yield* Component.useCallbackSync((setStateAction: React.SetStateAction) =>
Effect.andThen(
Ref.updateAndGet(ref, prevState => SetStateAction.value(setStateAction, prevState)),
v => setReactStateValue(v),
),
[ref])
return [reactStateValue, setValue]
})
export namespace useSubscriptionRefFromState {
export interface Options {
readonly equivalence?: Equivalence.Equivalence
}
}
export const useSubscriptionRefFromState: {
(
state: readonly [A, React.Dispatch>],
options?: useSubscriptionRefFromState.Options>,
): Effect.Effect, never, Scope.Scope>
} = Effect.fnUntraced(function*([value, setValue], options) {
const ref = yield* Component.useOnChange(() => Effect.tap(
SubscriptionRef.make(value),
ref => Effect.forkScoped(
Stream.runForEach(
Stream.changesWith(ref.changes, options?.equivalence ?? Equivalence.strict()),
v => Effect.sync(() => setValue(v)),
)
),
), [setValue])
yield* Component.useReactEffect(() => Ref.set(ref, value), [value])
return ref
})
export * from "effect/SubscriptionRef"