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 })