From a063329aa343d25bea40f71672094aa8d85c0b00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Fri, 17 Jan 2025 19:07:33 +0100 Subject: [PATCH] Documentation update --- packages/reffuse/src/Reffuse.ts | 96 +++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/packages/reffuse/src/Reffuse.ts b/packages/reffuse/src/Reffuse.ts index 1e8555f..d881af1 100644 --- a/packages/reffuse/src/Reffuse.ts +++ b/packages/reffuse/src/Reffuse.ts @@ -55,6 +55,15 @@ export class Reffuse { } + /** + * Reffuse equivalent to `React.useMemo`. + * + * `useMemo` will only recompute the memoized value by running the given synchronous effect when one of the deps has changed. \ + * Trying to run an asynchronous effect will throw. + * + * Changes to the Reffuse runtime or context will recompute the value in addition to the deps. + * You can disable this behavior by setting `doNotReExecuteOnRuntimeOrContextChange` to `true` in `options`. + */ useMemo( effect: Effect.Effect, deps?: React.DependencyList, @@ -68,6 +77,32 @@ export class Reffuse { ]) } + /** + * Reffuse equivalent to `React.useEffect`. + * + * Executes a synchronous effect wrapped into a Scope when one of the deps has changed. Trying to run an asynchronous effect will throw. + * + * The Scope is closed on every cleanup, i.e. when one of the deps has changed and the effect needs to be re-executed. \ + * Add finalizers to the Scope to handle cleanup logic. + * + * Changes to the Reffuse runtime or context will re-execute the effect in addition to the deps. + * You can disable this behavior by setting `doNotReExecuteOnRuntimeOrContextChange` to `true` in `options`. + * + * ### Example + * ``` + * useEffect(Effect.addFinalizer(() => Console.log("Component unmounted")).pipe( + * Effect.flatMap(() => Console.log("Component mounted")) + * )) + * ``` + * + * Plain React equivalent: + * ``` + * React.useEffect(() => { + * console.log("Component mounted") + * return () => { console.log("Component unmounted") } + * }) + * ``` + */ useEffect( effect: Effect.Effect, deps?: React.DependencyList, @@ -88,6 +123,33 @@ export class Reffuse { ]) } + /** + * Reffuse equivalent to `React.useLayoutEffect`. + * + * Executes a synchronous effect wrapped into a Scope when one of the deps has changed. Fires synchronously after all DOM mutations. \ + * Trying to run an asynchronous effect will throw. + * + * The Scope is closed on every cleanup, i.e. when one of the deps has changed and the effect needs to be re-executed. \ + * Add finalizers to the Scope to handle cleanup logic. + * + * Changes to the Reffuse runtime or context will re-execute the effect in addition to the deps. + * You can disable this behavior by setting `doNotReExecuteOnRuntimeOrContextChange` to `true` in `options`. + * + * ### Example + * ``` + * useLayoutEffect(Effect.addFinalizer(() => Console.log("Component unmounted")).pipe( + * Effect.flatMap(() => Console.log("Component mounted")) + * )) + * ``` + * + * Plain React equivalent: + * ``` + * React.useLayoutEffect(() => { + * console.log("Component mounted") + * return () => { console.log("Component unmounted") } + * }) + * ``` + */ useLayoutEffect( effect: Effect.Effect, deps?: React.DependencyList, @@ -122,6 +184,33 @@ export class Reffuse { return React.use(promise) } + /** + * An asynchronous and non-blocking alternative to `React.useEffect`. + * + * Forks an effect wrapped into a Scope in the background when one of the deps has changed. + * + * The Scope is closed on every cleanup, i.e. when one of the deps has changed and the effect needs to be re-executed. \ + * Add finalizers to the Scope to handle cleanup logic. + * + * Changes to the Reffuse runtime or context will re-execute the effect in addition to the deps. + * You can disable this behavior by setting `doNotReExecuteOnRuntimeOrContextChange` to `true` in `options`. + * + * ### Example + * ``` + * const timeRef = useRefFromEffect(DateTime.now) + * + * useFork(Effect.addFinalizer(() => Console.log("Cleanup")).pipe( + * Effect.map(() => Stream.repeatEffectWithSchedule( + * DateTime.now, + * Schedule.intersect(Schedule.forever, Schedule.spaced("1 second")), + * )), + * + * Effect.flatMap(Stream.runForEach(time => Ref.set(timeRef, time)), + * )), [timeRef]) + * + * const [time] = useRefState(timeRef) + * ``` + */ useFork( effect: Effect.Effect, deps?: React.DependencyList, @@ -163,6 +252,13 @@ export class Reffuse { ) } + /** + * Binds the state of a `SubscriptionRef` to the state of the React component. + * + * Returns a [value, setter] tuple just like `React.useState` and triggers a re-render everytime the value of 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. + */ useRefState(ref: SubscriptionRef.SubscriptionRef): [A, React.Dispatch>] { const runSync = this.useRunSync()