Debugging
storeName: label your stores
Every hook accepts an optional storeName string. It does two things:
- Error UI: the default error component includes the name, so you can tell which request failed.
- Debug logs: when
debugis 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:
| When | Message |
|---|---|
| Store state changes | user => { type: 'pending' } |
| Data arrives | user => { type: 'success', value: {...}, updatedAt: ... } |
| Dependency change | user refreshing due to deps, from/to: [1] [2] |
| Refresh scheduled | user: will refresh in 30000 |
| Unmount cancels timer | user: 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
| Prop | Type | Default | Description |
|---|---|---|---|
pollInterval | number | 1000 | How often to re-scan (ms) |
position | 'bottom-right' | 'bottom-left' | 'bottom-right' | Panel position |
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.