import * as LazyRef from "@typed/lazy-ref" import { Effect, pipe, Stream } from "effect" import * as React from "react" import { ReffuseExtension, type ReffuseNamespace, SetStateAction } from "reffuse" export const LazyRefExtension = ReffuseExtension.make(() => ({ useSubscribeLazyRefs< const Refs extends readonly LazyRef.LazyRef[], R, >( this: ReffuseNamespace.ReffuseNamespace, ...refs: Refs ): [...{ [K in keyof Refs]: Effect.Effect.Success }] { const [reactStateValue, setReactStateValue] = React.useState(this.useMemo( () => Effect.all(refs as readonly LazyRef.LazyRef[]), [], { doNotReExecuteOnRuntimeOrContextChange: true }, ) as [...{ [K in keyof Refs]: Effect.Effect.Success }]) this.useFork(() => pipe( refs.map(ref => Stream.changesWith(ref.changes, (x, y) => x === y)), streams => Stream.zipLatestAll(...streams), Stream.runForEach(v => Effect.sync(() => setReactStateValue(v as [...{ [K in keyof Refs]: Effect.Effect.Success }])) ), ), refs) return reactStateValue }, useLazyRefState( this: ReffuseNamespace.ReffuseNamespace, ref: LazyRef.LazyRef, ): [A, React.Dispatch>] { const [reactStateValue, setReactStateValue] = React.useState(this.useMemo( () => ref, [], { doNotReExecuteOnRuntimeOrContextChange: true }, )) this.useFork(() => Stream.runForEach( Stream.changesWith(ref.changes, (x, y) => x === y), v => Effect.sync(() => setReactStateValue(v)), ), [ref]) const setValue = this.useCallbackSync((setStateAction: React.SetStateAction) => LazyRef.update(ref, prevState => SetStateAction.value(setStateAction, prevState) ), [ref]) return [reactStateValue, setValue] }, }))