From 5c2d56ed91098af3130ad1d01f24118bd4544dad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Thu, 21 Aug 2025 03:50:06 +0200 Subject: [PATCH] useSubscribe --- packages/effect-fc/src/hooks/Hooks/index.ts | 2 +- .../src/hooks/Hooks/input/useOptionalInput.ts | 4 +-- .../effect-fc/src/hooks/Hooks/useSubscribe.ts | 31 +++++++++++++++++++ .../src/hooks/Hooks/useSubscribeRefs.ts | 27 ---------------- 4 files changed, 34 insertions(+), 30 deletions(-) create mode 100644 packages/effect-fc/src/hooks/Hooks/useSubscribe.ts delete mode 100644 packages/effect-fc/src/hooks/Hooks/useSubscribeRefs.ts diff --git a/packages/effect-fc/src/hooks/Hooks/index.ts b/packages/effect-fc/src/hooks/Hooks/index.ts index cfbc1ce..7d9443f 100644 --- a/packages/effect-fc/src/hooks/Hooks/index.ts +++ b/packages/effect-fc/src/hooks/Hooks/index.ts @@ -12,5 +12,5 @@ export * from "./useRefFromState.js" export * from "./useRefState.js" export * from "./useScope.js" export * from "./useStreamFromReactiveValues.js" -export * from "./useSubscribeRefs.js" +export * from "./useSubscribe.js" export * from "./useSubscribeStream.js" diff --git a/packages/effect-fc/src/hooks/Hooks/input/useOptionalInput.ts b/packages/effect-fc/src/hooks/Hooks/input/useOptionalInput.ts index 5b91e3e..c104952 100644 --- a/packages/effect-fc/src/hooks/Hooks/input/useOptionalInput.ts +++ b/packages/effect-fc/src/hooks/Hooks/input/useOptionalInput.ts @@ -5,7 +5,7 @@ import { useCallbackSync } from "../useCallbackSync.js" import { useFork } from "../useFork.js" import { useOnce } from "../useOnce.js" import { useRefState } from "../useRefState.js" -import { useSubscribeRefs } from "../useSubscribeRefs.js" +import { useSubscribe } from "../useSubscribe.js" export namespace useOptionalInput { @@ -101,7 +101,7 @@ export const useOptionalInput: { [options.schema, options.ref, internalRef, enabledRef], ) - const [enabled] = yield* useSubscribeRefs(enabledRef) + const [enabled] = yield* useSubscribe(enabledRef) const [value, setValue] = yield* useRefState(internalRef) return { value, setValue, enabled, setEnabled, error } }) diff --git a/packages/effect-fc/src/hooks/Hooks/useSubscribe.ts b/packages/effect-fc/src/hooks/Hooks/useSubscribe.ts new file mode 100644 index 0000000..d78ca2c --- /dev/null +++ b/packages/effect-fc/src/hooks/Hooks/useSubscribe.ts @@ -0,0 +1,31 @@ +import { Effect, Equivalence, pipe, type Readable, Stream, type Subscribable } from "effect" +import * as React from "react" +import { useFork } from "./useFork.js" +import { useOnce } from "./useOnce.js" + + +export const useSubscribe: { + & Subscribable.Subscribable)[]>( + ...elements: T + ): Effect.Effect< + { [K in keyof T]: Effect.Effect.Success | Stream.Stream.Success }, + Effect.Effect.Error | Stream.Stream.Error, + Effect.Effect.Context | Stream.Stream.Context + > +} = Effect.fnUntraced(function* & Subscribable.Subscribable)[]>( + ...elements: T +) { + const [reactStateValue, setReactStateValue] = React.useState(yield* useOnce(() => + Effect.all(elements.map(v => v.get)) + )) + + yield* useFork(() => pipe( + elements.map(ref => Stream.changesWith(ref.changes, Equivalence.strict())), + streams => Stream.zipLatestAll(...streams), + Stream.runForEach(v => + Effect.sync(() => setReactStateValue(v)) + ), + ), elements) + + return reactStateValue as any +}) diff --git a/packages/effect-fc/src/hooks/Hooks/useSubscribeRefs.ts b/packages/effect-fc/src/hooks/Hooks/useSubscribeRefs.ts deleted file mode 100644 index b6346c4..0000000 --- a/packages/effect-fc/src/hooks/Hooks/useSubscribeRefs.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Effect, Equivalence, pipe, Stream, SubscriptionRef } from "effect" -import * as React from "react" -import { useFork } from "./useFork.js" -import { useOnce } from "./useOnce.js" - - -export const useSubscribeRefs: { - []>( - ...refs: Refs - ): Effect.Effect<{ [K in keyof Refs]: Effect.Effect.Success }> -} = Effect.fnUntraced(function* []>( - ...refs: Refs -) { - const [reactStateValue, setReactStateValue] = React.useState(yield* useOnce(() => - Effect.all(refs as readonly SubscriptionRef.SubscriptionRef[]) - )) - - yield* useFork(() => pipe( - refs.map(ref => Stream.changesWith(ref.changes, Equivalence.strict())), - streams => Stream.zipLatestAll(...streams), - Stream.runForEach(v => - Effect.sync(() => setReactStateValue(v)) - ), - ), refs) - - return reactStateValue as any -})