Skip to main content

useFetch()

Fetch an Endpoint if it is not in cache or stale. Returns a thenable that works with React.use() -- use(useFetch(endpoint, args)) operates like useSuspense(), suspending when data is loading, returning denormalized data when available, and re-suspending on invalidation.

Usage

Parallel data loading

Since useFetch() and use() are separate calls, multiple fetches start in parallel — even when the first use() suspends. See the parallel fetches example below.

import { use } from 'react';
import { useFetch } from '@data-client/react';
import { PostResource, CommentResource } from './Resources';

function PostWithComments({ id }: { id: number }) {
  // Both fetches start in parallel
  const postPromise = useFetch(PostResource.get, { id });
  const commentsPromise = useFetch(CommentResource.getList, { postId: id });

  // use() reads the results — if the first suspends,
  // the second fetch is already in-flight
  const post = use(postPromise);
  const comments = use(commentsPromise);

  return (
    <article>
      <h3>{post.title}</h3>
      <p>{post.body}</p>
      <h4>Comments</h4>
      {comments.map(comment => (
        <div key={comment.id} className="listItem">
          <strong>{comment.author}</strong>: {comment.text}
        </div>
      ))}
    </article>
  );
}
render(<PostWithComments id={1} />);
🔴 Live Preview
Store

Prefetching

useFetch() can also be used standalone to ensure resources are available early in a render tree before they are needed.

tip

Use in combination with a data-binding hook (useCache(), useSuspense(), useDLE(), useLive()) in another component.

function MasterPost({ id }: { id: number }) {
useFetch(PostResource.get, { id });
// ...
}

Behavior

Expiry StatusFetchuse() behaviorresolvedConditions
Invalidyes1suspendsfalsenot in store, deletion, invalidation
Staleyes1suspendsfalse(first-render, arg change) & expiry < now
Validnoreturns datatruefetch completion
Errornothrows errortruefetch failed, caught by Error Boundary
noundefinednull used as second argument

When the store updates (e.g., via mutations or Controller.set()), the component re-renders and useFetch() returns updated denormalized data automatically.

note
  1. Identical fetches are automatically deduplicated
React Native

When using React Navigation, useFetch() will trigger fetches on focus if the data is considered stale.

Conditional Dependencies

Use null as the second argument to any Data Client hook means "do nothing."

// todo could be undefined if id is undefined
const todo = useFetch(TodoResource.get, id ? { id } : null);

Types

function useFetch(
endpoint: ReadEndpoint,
...args: Parameters<typeof endpoint> | [null]
): (PromiseLike<any> & { resolved: boolean }) | undefined;

Examples

Checking fetch status

Use promise.resolved to check whether data is still loading:

function MasterPost({ id }: { id: number }) {
const promise = useFetch(PostResource.get, { id });
if (!promise.resolved) {
// fetch is in-flight
}
// ...
}

NextJS Preload

To prevent fetch waterfalls in NextJS, sometimes you might need to add preloads to top level routes.

More Demos