diff --git a/packages/example/src/routes/promise.tsx b/packages/example/src/routes/promise.tsx
index da200db..d5c9b57 100644
--- a/packages/example/src/routes/promise.tsx
+++ b/packages/example/src/routes/promise.tsx
@@ -15,13 +15,11 @@ const Result = Schema.Tuple(Schema.String)
type Result = typeof Result.Type
function RouteComponent() {
- const promise = R.usePromise(HttpClient.HttpClient.pipe(
+ const promise = R.usePromiseScoped(HttpClient.HttpClient.pipe(
Effect.flatMap(client => client.get("https://www.uuidtools.com/api/generate/v4")),
HttpClient.withTracerPropagation(false),
Effect.flatMap(res => res.json),
Effect.flatMap(Schema.decodeUnknown(Result)),
-
- Effect.scoped,
))
return (
diff --git a/packages/example/src/routes/tests.tsx b/packages/example/src/routes/tests.tsx
index 6961e11..82b6919 100644
--- a/packages/example/src/routes/tests.tsx
+++ b/packages/example/src/routes/tests.tsx
@@ -1,8 +1,6 @@
import { R } from "@/reffuse"
import { createFileRoute } from "@tanstack/react-router"
-import { GetRandomValues, makeUuid4 } from "@typed/id"
import { Console, Effect } from "effect"
-import { useMemo, useState } from "react"
export const Route = createFileRoute("/tests")({
@@ -16,24 +14,10 @@ function RouteComponent() {
// ), [])
// console.log(value)
- // R.useFork(Effect.addFinalizer(() => Console.log("cleanup")).pipe(
- // Effect.andThen(Console.log("ouient")),
- // Effect.delay("1 second"),
- // ))
-
- const runPromise = R.useRunPromise()
- const [, setValue] = useState("")
-
- const promise = useMemo(() => makeUuid4.pipe(
- Effect.provide(GetRandomValues.CryptoRandom),
- Effect.tap(id => Effect.sync(() => setValue(id))),
- Effect.andThen(Console.log),
+ R.useFork(Effect.addFinalizer(() => Console.log("cleanup")).pipe(
+ Effect.andThen(Console.log("ouient")),
Effect.delay("1 second"),
-
- runPromise,
- ), [runPromise])
-
- console.log(promise)
+ ))
return
Hello "/tests"!
diff --git a/packages/reffuse/src/Reffuse.ts b/packages/reffuse/src/Reffuse.ts
index cc1755f..f3d56ec 100644
--- a/packages/reffuse/src/Reffuse.ts
+++ b/packages/reffuse/src/Reffuse.ts
@@ -5,6 +5,7 @@ import * as ReffuseRuntime from "./ReffuseRuntime.js"
import * as SetStateAction from "./SetStateAction.js"
+// MAYBE: make it an Effect and match the R parameter?
export class Reffuse {
constructor(
@@ -305,29 +306,25 @@ export class Reffuse {
const runSync = this.useRunSync()
const runPromise = this.useRunPromise()
- // Calculate an initial version of the value so that it can be accessed during the first render
- const initialScope = React.useMemo(() => runSync(Scope.make(options?.finalizerExecutionStrategy)), [])
- const initialValue = React.useMemo(() => runPromise(Effect.provideService(effect, Scope.Scope, initialScope), options), [])
-
- // Keep track of the state of the initial scope
- const initialScopeClosed = React.useRef(false)
-
- const [value, setValue] = React.useState(initialValue)
+ const [value, setValue] = React.useState(new Promise(() => {}))
React.useEffect(() => {
- const closeInitialScopeIfNeeded = Scope.close(initialScope, Exit.void).pipe(
- Effect.andThen(Effect.sync(() => { initialScopeClosed.current = true })),
- Effect.when(() => !initialScopeClosed.current),
- )
+ const controller = new AbortController()
+ const signal = AbortSignal.any([
+ controller.signal,
+ ...options?.signal ? [options.signal] : [],
+ ])
- const scope = closeInitialScopeIfNeeded.pipe(
- Effect.andThen(Scope.make(options?.finalizerExecutionStrategy)),
- runSync,
- )
+ const scope = runSync(Scope.make(options?.finalizerExecutionStrategy))
+ setValue(runPromise(Effect.provideService(effect, Scope.Scope, scope), {
+ ...options,
+ signal,
+ }))
- setValue(runPromise(Effect.provideService(effect, Scope.Scope, initialScope), options))
-
- return () => { runSync(Scope.close(scope, Exit.void)) }
+ return () => {
+ controller.abort()
+ runSync(Scope.close(scope, Exit.void))
+ }
}, [
...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runSync, runPromise],
...(deps ?? []),
@@ -371,32 +368,6 @@ export class Reffuse {
return [reactStateValue, setValue]
}
- /**
- * Binds the state of a `LazyRef` from the `@typed/lazy-ref` package to the state of the React component.
- *
- * Returns a [value, setter] tuple just like `React.useState` and triggers a re-render everytime the value held by the ref changes.
- *
- * Note that the rules of React's immutable state still apply: updating a ref with the same value will not trigger a re-render.
- */
- // useLazyRefState(ref: LazyRef.LazyRef): [A, React.Dispatch>] {
- // const runSync = this.useRunSync()
-
- // const initialState = React.useMemo(() => runSync(ref), [])
- // const [reactStateValue, setReactStateValue] = React.useState(initialState)
-
- // this.useFork(Stream.runForEach(ref.changes, v => Effect.sync(() =>
- // setReactStateValue(v)
- // )), [ref])
-
- // const setValue = React.useCallback((setStateAction: React.SetStateAction) =>
- // runSync(LazyRef.update(ref, prevState =>
- // SetStateAction.value(setStateAction, prevState)
- // )),
- // [ref])
-
- // return [reactStateValue, setValue]
- // }
-
}
diff --git a/packages/reffuse/src/ReffuseContext.tsx b/packages/reffuse/src/ReffuseContext.tsx
index dbca682..a7b49a5 100644
--- a/packages/reffuse/src/ReffuseContext.tsx
+++ b/packages/reffuse/src/ReffuseContext.tsx
@@ -3,6 +3,7 @@ import React from "react"
import * as ReffuseRuntime from "./ReffuseRuntime.js"
+// TODO: merge this with the Provider, just like React 19 contexts
export class ReffuseContext {
readonly Context = React.createContext>(null!)