StunkStunk
Async

Combine Async Chunks

Merge multiple async chunks into a single reactive state object.

combineAsyncChunks() merges multiple async chunks into a single reactive chunk. Instead of subscribing to each chunk individually, you get one unified state with combined loading, error, and data — keyed by the names you provide.

import { asyncChunk, combineAsyncChunks } from "stunk/query";

const userChunk = asyncChunk(() => fetchUser());
const postsChunk = asyncChunk(() => fetchPosts());

const combined = combineAsyncChunks({ user: userChunk, posts: postsChunk });

combined.get();
// {
//   loading: true,
//   error: null,
//   errors: {},
//   data: { user: null, posts: null }
// }

State shape

PropertyTypeDescription
loadingbooleantrue if any source chunk is loading
errorError | nullThe first error encountered across all chunks
errorsPartial<Record<key, Error>>Per-chunk errors, keyed by name
dataRecord<key, T | null>Per-chunk data, keyed by name

Basic usage

import { asyncChunk, combineAsyncChunks } from "stunk/query";

const userChunk = asyncChunk(() => fetchUser());
const settingsChunk = asyncChunk(() => fetchSettings());
const notifChunk = asyncChunk(() => fetchNotifications());

const appData = combineAsyncChunks({
  user: userChunk,
  settings: settingsChunk,
  notifications: notifChunk,
});

appData.subscribe(({ loading, error, data }) => {
  if (loading) return;
  console.log(data.user, data.settings, data.notifications);
});

Error handling

error holds the first error encountered. errors gives per-chunk granularity:

const { error, errors, data } = appData.get();

if (errors.user) console.error("User failed:", errors.user.message);
if (errors.settings) console.error("Settings failed:", errors.settings.message);

In React

import { asyncChunk, combineAsyncChunks } from "stunk/query";
import { useChunkValue } from "stunk/react";

const userChunk = asyncChunk(() => fetchUser());
const postsChunk = asyncChunk(() => fetchPosts());
const combined = combineAsyncChunks({ user: userChunk, posts: postsChunk });

function Dashboard() {
  const { loading, errors, data } = useChunkValue(combined);

  if (loading) return <p>Loading...</p>;

  return (
    <div>
      {errors.user && <p>Failed to load user: {errors.user.message}</p>}
      {errors.posts && <p>Failed to load posts: {errors.posts.message}</p>}
      {data.user && <p>Welcome, {data.user.name}</p>}
      {data.posts && (
        <ul>
          {data.posts.map((p) => (
            <li key={p.id}>{p.title}</li>
          ))}
        </ul>
      )}
    </div>
  );
}

loading is true as long as any source chunk is still loading — even if others have already resolved. Each chunk fetches independently and the combined state updates reactively as each one completes.


What's next?

On this page