Skip to main content

Debugging

storeName: label your stores​

Every hook accepts an optional storeName string. It does two things:

  1. Error UI: the default error component includes the name, so you can tell which request failed.
  2. Debug logs: when debug is enabled, every log line is prefixed with the store name.
const userStore = useRemoteData(() => fetchUser(id), {
storeName: 'user',
dependencies: [id],
});

If the request fails, the default error component renders "Failed request for store user" instead of the generic "Failed request".

Combined stores​

When you combine stores with RemoteDataStore.all(), the combined store's name is the comma-separated list of its constituents:

const userStore = useRemoteData(() => fetchUser(id), { storeName: 'user' });
const postsStore = useRemoteData(() => fetchPosts(id), { storeName: 'posts' });

const allStore = RemoteDataStore.all(userStore, postsStore);
// allStore.storeName → "user, posts"

Dynamic data​

For useRemoteDataMap, the key is appended to the name:

const itemsStore = useRemoteDataMap((page: number) => fetchItems(page), { storeName: 'items' });

itemsStore.get(3);
// store.storeName → "items(3)"

Custom error component​

The storeName is passed to your error render prop via ErrorProps:

<Await
store={userStore}
error={({ errors, retry, storeName }) => (
<div>
<p>Failed{storeName ? ` loading ${storeName}` : ''}.</p>
<button onClick={retry}>Retry</button>
</div>
)}
>
{(user) => <h1>{user.name}</h1>}
</Await>

debug: trace state transitions​

Pass debug: console.warn (or any function with the same signature) to see every state change in your console:

const store = useRemoteData(() => fetchUser(id), {
storeName: 'user',
debug: console.warn,
dependencies: [id],
});

This logs:

WhenMessage
Store state changesuser => { type: 'pending' }
Data arrivesuser => { type: 'success', value: {...}, updatedAt: ... }
Dependency changeuser refreshing due to deps, from/to: [1] [2]
Refresh scheduleduser: will refresh in 30000
Unmount cancels timeruser: cancelled refresh on unmount

Every message is prefixed with storeName when set, so you can filter your console by store name.

Scoping debug to development​

You probably don't want debug logs in production:

const store = useRemoteData(() => fetchUser(id), {
storeName: 'user',
debug: process.env.NODE_ENV === 'development' ? console.warn : undefined,
});

Mutations​

useRemoteUpdate accepts debug and storeName in its options too:

const saveStore = useRemoteUpdate((params: { name: string }) => api.createUser(params), {
storeName: 'createUser',
debug: console.warn,
refreshes: [usersStore],
});

Inspecting state directly​

Every store exposes its current state via store.current. You can log it anywhere:

console.log(store.current);
// { type: 'success', value: { name: 'Alice' }, updatedAt: 2024-01-15T... }

This is a plain object: you can JSON.stringify it, pass it to a logger, or inspect it in React DevTools. The type field tells you exactly which state the store is in: 'initial', 'pending', 'failed', 'success', 'stale-immediate', 'stale-initial', or 'stale-pending'.

<RemoteDataDevtools />: visual panel​

Drop the devtools component anywhere in your app to see all active stores at a glance:

import { RemoteDataDevtools } from 'use-remote-data';

function App() {
return (
<>
<Router />
{process.env.NODE_ENV === 'development' && <RemoteDataDevtools />}
</>
);
}

The panel scans the React fiber tree and finds every RemoteDataStore passed as a prop to any component. No registration, no wrapper hooks, no provider. It shows:

  • Store name and current state (with color-coded indicators)
  • Data preview (truncated JSON for success, error message for failures)
  • Time since last fetch
  • Which component owns the store

Stores are deduplicated: if the same store is passed to 10 components, it shows once. Shared stores (useSharedRemoteData) with the same name are also deduplicated.

Options​

PropTypeDefaultDescription
pollIntervalnumber1000How often to re-scan (ms)
position'bottom-right' | 'bottom-left''bottom-right'Panel position
Try it on this site

Click the devtools button in the bottom-left corner of this page, then run any code snippet. You'll see the stores appear in the panel as they fetch and resolve.