createResource: Async Data Coordination & <Suspense> Trapping
- Last updated
- Prerequisites:
- SolidJS createSignal
- Promises and Suspense
- solidjs
- createResource
- suspense
- async
- fetching
- signals
Read at your depth
The practical view
`createResource` is Solid's built-in primitive for handling asynchronous data fetching. `const [data, { mutate, refetch }] = createResource(sourceSignal, fetcherFn);`. `data()` returns the fetched value, `data.loading` indicates active requests, and `data.error` captures failures. When used inside a `<Suspense fallback={<Loading />}>` boundary, Solid automatically suspends the boundary until the resource resolves.
The same idea in other frameworks
React 19 `use(fetchPromise)` inside `<Suspense>`.Angular 19 `resource()` / `rxResource()` signal API.`<Suspense>` with top-level `await` in `<script setup>`.Svelte `{#await promise}<Loading />{:then data}...{/await}`.Legacy vs modern
Manual async/await Signal State vs createResource + Suspense
Manual fetch orchestration causes race conditions and loading state boilerplate; `createResource` binds directly to Suspense.
createEffect(async () => { setLoading(true); setData(await fetch()); }); // ❌ Race conditionsconst [user] = createResource(userId, fetchUser); // ✅ NEW: Auto-cancels stale requests & binds to SuspenseInterview gotchas
Context
Interviewers test your knowledge of asynchronous concurrency control in reactive systems.
The mechanical answer
`createResource` maintains an internal monotonic sequence counter (request ID) for each fetch invocation. When the source signal updates (e.g. `userId` changes from 1 to 2), the sequence number increments. When an asynchronous fetch promise resolves, `createResource` checks if the resolved request ID matches the latest sequence counter. If an older request (user 1) resolves after a newer request (user 2), the older result is silently discarded.
Trap
Do not implement manual cancellation booleans inside custom fetchers; `createResource` handles stale response discarding automatically.
Context
Checks knowledge of resource access semantics in non-suspense contexts.
The mechanical answer
Yes. If `data()` is read outside of a `<Suspense>` boundary, it will return `undefined` while pending (or its initial value if provided), and `data.loading` will return `true`. It will not throw or crash; it simply renders standard conditional checks (e.g. `{data() ? data().name : 'Loading...'}`).
Trap
Using `data().name` without optional chaining or Suspense when `data()` is `undefined` will trigger a JavaScript `TypeError: Cannot read property of undefined`.