From 6b74b9a3b282c5a08b2df06b713a3064b3e17488 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Fri, 28 Mar 2025 21:09:27 +0100 Subject: [PATCH] useMemoScoped refactoring --- packages/reffuse/src/ReffuseHelpers.ts | 53 ++++++++++++-------------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/packages/reffuse/src/ReffuseHelpers.ts b/packages/reffuse/src/ReffuseHelpers.ts index 5553a37..b66c241 100644 --- a/packages/reffuse/src/ReffuseHelpers.ts +++ b/packages/reffuse/src/ReffuseHelpers.ts @@ -108,41 +108,38 @@ export abstract class ReffuseHelpers { ): A { const runSync = this.useRunSync() - // Calculate an initial version of the value so that it can be accessed during the first render - const [initialScope, initialValue] = React.useMemo(() => Scope.make(options?.finalizerExecutionStrategy).pipe( - Effect.flatMap(scope => effect().pipe( - Effect.provideService(Scope.Scope, scope), - Effect.map(value => [scope, value] as const), - )), - + const [isInitialRun, initialScope, initialValue] = React.useMemo(() => Effect.Do.pipe( + Effect.bind("isInitialRun", () => Ref.make(true)), + Effect.bind("scope", () => Scope.make(options?.finalizerExecutionStrategy)), + Effect.bind("value", ({ scope }) => Effect.provideService(effect(), Scope.Scope, scope)), + Effect.map(({ isInitialRun, scope, value }) => [isInitialRun, scope, value] as const), runSync, ), []) - // Keep track of the state of the initial scope - const initialScopeClosed = React.useRef(false) - const [value, setValue] = React.useState(initialValue) - React.useEffect(() => { - const closeInitialScopeIfNeeded = Scope.close(initialScope, Exit.void).pipe( - Effect.andThen(Effect.sync(() => { initialScopeClosed.current = true })), - Effect.when(() => !initialScopeClosed.current), - ) + React.useEffect(() => isInitialRun.pipe( + Effect.if({ + onTrue: () => Ref.set(isInitialRun, false).pipe( + Effect.map(() => + () => runSync(Scope.close(initialScope, Exit.void)) + ) + ), - const [scope, value] = closeInitialScopeIfNeeded.pipe( - Effect.andThen(Scope.make(options?.finalizerExecutionStrategy).pipe( - Effect.flatMap(scope => effect().pipe( - Effect.provideService(Scope.Scope, scope), - Effect.map(value => [scope, value] as const), - )) - )), + onFalse: () => Effect.Do.pipe( + Effect.bind("scope", () => Scope.make(options?.finalizerExecutionStrategy)), + Effect.bind("value", ({ scope }) => Effect.provideService(effect(), Scope.Scope, scope)), + Effect.tap(({ value }) => + Effect.sync(() => setValue(value)) + ), + Effect.map(({ scope }) => + () => runSync(Scope.close(scope, Exit.void)) + ), + ), + }), - runSync, - ) - - setValue(value) - return () => { runSync(Scope.close(scope, Exit.void)) } - }, [ + runSync, + ), [ ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runSync], ...deps, ])