import { Effect, Equivalence, Stream, SubscriptionRef } from "effect"
import { Lens } from "effect-lens"
import * as React from "react"
import * as Component from "./Component.js"
import * as SetStateAction from "./SetStateAction.js"
export * from "effect-lens/Lens"
export declare namespace useState {
export interface Options {
readonly equivalence?: Equivalence.Equivalence
}
}
export const useState = Effect.fnUntraced(function* (
lens: Lens.Lens,
options?: useState.Options>,
): Effect.fn.Return>], ER | EW, RR | RW> {
const [reactStateValue, setReactStateValue] = React.useState(yield* Component.useOnMount(() => Lens.get(lens)))
yield* Component.useReactEffect(() => Effect.forkScoped(
Stream.runForEach(
Stream.changesWith(lens.changes, options?.equivalence ?? Equivalence.strictEqual()),
v => Effect.sync(() => setReactStateValue(v)),
)
), [lens])
const setValue = yield* Component.useCallbackSync(
(setStateAction: React.SetStateAction) => Effect.tap(
Lens.updateAndGet(lens, prevState => SetStateAction.value(setStateAction, prevState)),
v => Effect.sync(() => setReactStateValue(v)),
),
[lens],
)
return [reactStateValue, setValue]
})
export declare namespace useFromReactState {
export interface Options {
readonly equivalence?: Equivalence.Equivalence
}
}
export const useFromReactState = Effect.fnUntraced(function* (
[value, setValue]: readonly [A, React.Dispatch>],
options?: useFromReactState.Options>,
): Effect.fn.Return> {
const lens = yield* Component.useOnMount(() => Effect.map(
SubscriptionRef.make(value),
Lens.fromSubscriptionRef,
))
yield* Component.useReactEffect(() => Effect.forkScoped(Stream.runForEach(
Stream.changesWith(lens.changes, options?.equivalence ?? Equivalence.strictEqual()),
v => Effect.sync(() => setValue(v)),
)), [setValue])
yield* Component.useReactEffect(() => Lens.set(lens, value), [value])
return lens
})