Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | 28x 28x 28x 28x 28x 28x 28x 28x 16x 16x 28x 11x 11x 11x 1x 11x 5x 5x 5x 6x 6x 6x 11x 28x 26x 26x 26x 20x 28x | import { useCallback, useEffect, useRef, useState } from "react";
import { Effect, Fiber } from "effect";
import { type DomainError } from "@repo/effect-utils";
type RunEffectResult<A, E> = {
data: A | null;
error: E | null;
loading: boolean;
run: () => void;
};
export function useRunEffect<A, E = DomainError>(
effect: Effect.Effect<A, E>,
options?: {
immediate?: boolean;
onSuccess?: (data: A) => void;
onError?: (error: E) => void;
},
): RunEffectResult<A, E> {
const [data, setData] = useState<A | null>(null);
const [error, setError] = useState<E | null>(null);
const [loading, setLoading] = useState(false);
const immediate = options?.immediate ?? false;
const onSuccessRef = useRef(options?.onSuccess);
const onErrorRef = useRef(options?.onError);
// The fiber runs the match effect, which returns void.
// The error type is never because match handles both success and failure.
const fiberRef = useRef<Fiber.RuntimeFiber<void, never> | null>(null);
useEffect(() => {
onSuccessRef.current = options?.onSuccess;
onErrorRef.current = options?.onError;
}, [options?.onError, options?.onSuccess]);
const run = useCallback(() => {
setLoading(true);
setError(null);
// Cancel previous execution if running
if (fiberRef.current) {
Effect.runFork(Fiber.interrupt(fiberRef.current));
}
const fiber = Effect.runFork(
Effect.match(effect, {
onFailure: (e) => {
setError(e);
setLoading(false);
onErrorRef.current?.(e);
},
onSuccess: (a) => {
setData(a);
setLoading(false);
onSuccessRef.current?.(a);
},
}),
);
fiberRef.current = fiber;
}, [effect]);
useEffect(() => {
Iif (immediate) {
run();
}
return () => {
// Cleanup on unmount
if (fiberRef.current) {
Effect.runFork(Fiber.interrupt(fiberRef.current));
}
};
}, [immediate, run]);
return { data, error, loading, run };
}
|