From 87e7b74ed64c21b7f3288ca97da981fea341aec5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Mon, 3 Nov 2025 01:21:58 +0100 Subject: [PATCH] Fix --- packages/effect-fc/src/Component.ts | 22 +++++++++++++++++++--- packages/example/src/routes/form.tsx | 10 +++++----- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/packages/effect-fc/src/Component.ts b/packages/effect-fc/src/Component.ts index 7252f79..ceacc70 100644 --- a/packages/effect-fc/src/Component.ts +++ b/packages/effect-fc/src/Component.ts @@ -490,7 +490,7 @@ export const useOnMount: { }) export namespace useOnChange { - export type Options = useScope.Options + export interface Options extends useScope.Options {} } export const useOnChange: { @@ -578,6 +578,22 @@ export const useReactLayoutEffect: { React.useLayoutEffect(() => runReactEffect(runtime, f, options), deps) }) +export const useRunSync: { + (): Effect.Effect<(effect: Effect.Effect) => A, never, Scope.Scope | R> +} = Effect.fnUntraced(function* ( + f: (...args: Args) => Effect.Effect, + deps: React.DependencyList, +) { + // biome-ignore lint/style/noNonNullAssertion: context initialization + const runtimeRef = React.useRef>(null!) + runtimeRef.current = yield* Effect.runtime() + + Runtime.runSync() + + // biome-ignore lint/correctness/useExhaustiveDependencies: use of React.DependencyList + return React.useCallback((...args: Args) => Runtime.runSync(runtimeRef.current)(f(...args)), deps) +}) + export const useCallbackSync: { ( f: (...args: Args) => Effect.Effect, @@ -613,13 +629,13 @@ export const useCallbackPromise: { }) export namespace useContext { - export type Options = useOnChange.Options + export interface Options extends useOnChange.Options {} } export const useContext = ( layer: Layer.Layer, options?: useContext.Options, -): Effect.Effect, E, RIn> => useOnChange(() => Effect.context().pipe( +): Effect.Effect, E, Scope.Scope | RIn> => useOnChange(() => Effect.context().pipe( Effect.map(context => ManagedRuntime.make(Layer.provide(layer, Layer.succeedContext(context)))), Effect.tap(runtime => Effect.addFinalizer(() => runtime.disposeEffect)), Effect.andThen(runtime => runtime.runtimeEffect), diff --git a/packages/example/src/routes/form.tsx b/packages/example/src/routes/form.tsx index 54643e3..4c10e5b 100644 --- a/packages/example/src/routes/form.tsx +++ b/packages/example/src/routes/form.tsx @@ -39,10 +39,10 @@ class RegisterForm extends Effect.Service()("RegisterForm", { ), initialEncodedValue: { email: "", password: "", birth: Option.none() }, - onSubmit: v => Effect.sleep("500 millis").pipe( - Effect.andThen(Console.log(v)), - Effect.andThen(Effect.sync(() => alert("Done!"))), - ), + onSubmit: Effect.fnUntraced(function*(v) { + yield* Effect.sleep("500 millis") + return v + }), debounce: "500 millis", }) }) {} @@ -93,7 +93,7 @@ class RegisterFormView extends Component.makeUntraced("RegisterFormView")(functi Match.tag("Initial", () => <>), Match.tag("Running", () => Submitting...), Match.tag("Success", () => Submitted successfully!), - Match.tag("Failure", v => Error: {v.cause.toString()}), + Match.tag("Failure", e => Error: {e.cause.toString()}), Match.exhaustive, )}