API reference/fetchium/react

fetchium/react

fetchium/react

React hooks for using Fetchium queries in React components. Built on top of Signalium's useReactive hook.

ts
import { useQuery } from 'fetchium/react';

Hooks

useQuery

ts
function useQuery<T extends Query>(
  QueryClass: new () => T,
  params?: ExtractQueryParams<T>,
): QueryPromise<T>;

React hook for fetching a query. Subscribes the component to the query's reactive state, re-rendering when the query result changes. Internally uses Signalium's useReactive to bridge the reactive signal system with React's rendering cycle.

Parameters

ParameterTypeDescription
QueryClassnew () => TThe query class to instantiate and execute. Must extend Query or RESTQuery.
paramsExtractQueryParams<T>Parameters matching the query's params shape. Optional if the query has no required params. Values can be Signalium Signals for reactive parameter changes.

Returns

QueryPromise<T> — a DiscriminatedReactivePromise that provides the query state.

The returned promise object has the following properties:

PropertyTypeDescription
valueQueryResult<T>The resolved query result. Reading this while pending triggers React Suspense. Returns a deep clone to avoid accidental mutation of cached entities.
isReadybooleantrue once the query has loaded a value at least once. Use for type narrowing on value.
isPendingbooleantrue while the query is loading. Also true during refetches, even if a value already exists.
isResolvedbooleantrue when the most recent execution resolved successfully.
isRejectedbooleantrue when the most recent execution failed.
errorunknownThe error if isRejected is true.

The resolved QueryResult<T> includes pagination helpers:

PropertyTypeDescription
__refetch()() => QueryPromise<T>Triggers a refetch and returns a new promise.
__fetchNext()() => Promise<QueryResult<T>>Fetches the next page (if configured via fetchNext).
__hasNextbooleanWhether there is a next page available.
__isFetchingNextbooleanWhether a next-page request is currently in flight.

Requirements

  • A QueryClient must be provided via QueryClientContext using Signalium's ContextProvider.
  • The component must be wrapped in a Signalium component() or use useReactive for the reactive system to function.

Example

tsx
import { component } from 'signalium/react';
import { useQuery } from 'fetchium/react';

class GetUsers extends RESTQuery {
  path = '/api/users';

  result = {
    users: t.array(t.entity(User)),
    total: t.number,
  };
}

const UserList = component(() => {
  const query = useQuery(GetUsers);

  if (query.isPending) {
    return <div>Loading...</div>;
  }

  if (query.isRejected) {
    return <div>Error: {String(query.error)}</div>;
  }

  const { users, total } = query.value;

  return (
    <div>
      <h2>Users ({total})</h2>
      <ul>
        {users.map((user) => (
          <li key={user.id}>{user.name}</li>
        ))}
      </ul>
    </div>
  );
});

With parameters

tsx
const UserProfile = component(({ userId }: { userId: string }) => {
  const query = useQuery(GetUser, { id: userId });

  return <div>{query.value.name}</div>;
});

With reactive parameters

tsx
import { signal } from 'signalium';

const searchTerm = signal('');

const SearchResults = component(() => {
  const query = useQuery(SearchUsers, { q: searchTerm });

  // Component re-renders when searchTerm changes and the query refetches
  return <div>{query.value.results.length} results</div>;
});

Notes

  • useQuery calls useReactive twice internally: once for the query itself and once to subscribe to the resolved value for deep entity tracking via Signalium's CONSUME_DEEP protocol.
  • The value property returns a deep clone of the query result to prevent accidental mutation of the entity cache. Use draft() from fetchium if you need a mutable copy for mutations.
  • When used with React Suspense, reading .value on a pending query will suspend the component.
Previous
fetchium