Skip to content
Source
Sign inSign up

query.ts

42 lines1.6 KB

1import { useAtomRefresh, useAtomValue } from "@effect/atom-react";
2import * as Cause from "effect/Cause";
3import { AsyncResult, Atom } from "effect/reactivity";
4​
5const EMPTY_ASYNC_RESULT_ATOM = Atom.make(AsyncResult.initial<never, never>(false)).pipe(
6 Atom.withLabel("mobile-environment-query:empty"),
7);
8​
9export interface EnvironmentQueryView<A> {
10 readonly data: A | null;
11 readonly successResult: AsyncResult.Success<A, unknown> | null;
12 readonly error: string | null;
13 readonly failure: unknown;
14 readonly isPending: boolean;
15 readonly isSuccess: boolean;
16 readonly refresh: () => void;
18​
19function formatError(cause: Cause.Cause<unknown>): string {
20 const error = Cause.squash(cause);
21 return error instanceof Error && error.message.trim().length > 0
22 ? error.message
23 : "The environment request failed.";
25​
26export function useEnvironmentQuery<A, E>(
27 atom: Atom.Atom<AsyncResult.AsyncResult<A, E>> | null,
28): EnvironmentQueryView<A> {
29 const selectedAtom = atom ?? EMPTY_ASYNC_RESULT_ATOM;
30 const result = useAtomValue(selectedAtom);
31 const refresh = useAtomRefresh(selectedAtom);
32 return {
33 data: AsyncResult.getOrElse(result, () => null),
34 // Data may be structurally shared; only a settled success proves a new response.
35 successResult: result._tag === "Success" && !result.waiting ? result : null,
36 failure: result._tag === "Failure" ? Cause.squash(result.cause) : null,
37 error: result._tag === "Failure" ? formatError(result.cause) : null,
38 isPending: atom !== null && result.waiting,
39 isSuccess: result._tag === "Success",
40 refresh,
41 };