Skip to content
effective-rsc
DocumentationIndex

Reading a Server Function from the browser

queryAtom exposes the author lookup as atom state, with typed results and ServerFnError failures.

80_author-preview.tsx
'use client';

import { useAtom } from '@effect/atom-react';
import { Cause, Option } from 'effect';
import { AsyncResult } from 'effect/unstable/reactivity';
import { ServerFn, type ServerFnError } from 'effective-rsc/client';

import { lookupAuthor } from './70_lookup-author';

const authorQuery = ServerFn.queryAtom(lookupAuthor);

const describe = (cause: Cause.Cause<ServerFnError>) => {
  const error = Option.getOrUndefined(Cause.findErrorOption(cause));
  switch (error?._tag) {
    case 'ServerFnInputError':
      return `The lookup was rejected: ${error.detail.message}`;
    case 'ServerFnTransportError':
      return 'The lookup request could not complete.';
    case 'ServerFnDefect':
      return `The lookup failed. Reference ${error.digest}.`;
    default:
      return 'The lookup failed.';
  }
};

export function AuthorPreview({ authorId }: { readonly authorId: string }) {
  const [author, lookup] = useAtom(authorQuery);

  return (
    <div>
      <button onClick={() => lookup([{ authorId }])} type='button'>
        Preview author
      </button>
      <p>
        {AsyncResult.match(author, {
          onInitial: () => 'No author previewed yet.',
          onSuccess: ({ value }) =>
            value._tag === 'Found' ? value.name : `Unavailable. Retry in ${value.retryAfter}s.`,
          onFailure: ({ cause }) => describe(cause),
        })}
      </p>
    </div>
  );
}