Refreshing Data
Sometimes data becomes out-of-date.
use-remote-data supports refreshing through an optional refresh: RefreshStrategy parameter to the hook.
A RefreshStrategy is a function that decides whether to keep data or mark it stale.
By time
Here is an example where data is considered stale after 2 seconds.
In the <Await> render prop,
you can check the second argument (isStale)
to decide whether to let the user see old data or a loading indicator.
import { RefreshStrategy, useRemoteData, Await } from 'use-remote-data';
let i = 0;
const freshData = (): Promise<number> =>
new Promise((resolve) => {
i += 1;
setTimeout(() => resolve(i), 1000);
});
export function Component() {
const store = useRemoteData(freshData, {
refresh: RefreshStrategy.afterMillis(2000),
});
return (
<Await store={store}>
{(num, isStale) => (
<span style={{ color: isStale ? 'darkgray' : 'black' }}>
{num}
</span>
)}
</Await>
);
}
Only Sometimes?
You can enable or disable refreshing dynamically by swapping the refresh strategy in or out. For instance:
import { useState } from 'react';
import { RefreshStrategy, useRemoteData, Await } from 'use-remote-data';
let i = 0;
const freshData = (): Promise<number> =>
new Promise((resolve) => {
i += 1;
setTimeout(() => resolve(i), 1000);
});
export function Component() {
const [autoRefresh, setAutoRefresh] = useState(true);
const store = useRemoteData(freshData, {
refresh: autoRefresh ? RefreshStrategy.afterMillis(1000) : undefined,
});
return (
<div>
<label>
Autorefresh:
<input
type="checkbox"
onChange={(e) => setAutoRefresh(!autoRefresh)}
checked={autoRefresh}
/>
</label>
<br />
<Await store={store}>
{(num, isStale) => (
<span style={{ color: isStale ? 'darkgray' : 'black' }}>
{num}
</span>
)}
</Await>
</div>
);
}
Poll until valid data
Something that comes up sometimes is APIs which require you to poll.
use-remote-data supports this through RefreshStrategy.pollUntil
import { RefreshStrategy, useRemoteData, Await } from 'use-remote-data';
let i = 0;
const freshData = (): Promise<number> =>
new Promise((resolve) => {
i += 1;
setTimeout(() => resolve(i), 1000);
});
export function Component() {
const store = useRemoteData(freshData, {
refresh: RefreshStrategy.pollUntil((x) => x > 2, 1000),
storeName: 'polling-store',
});
return (
<Await store={store}>
{(num, isStale) =>
isStale ? <span>stale data {num}</span> : <span>{num}</span>
}
</Await>
);
}
Refresh on Dependency Change
useRemoteData and useRemoteDataMap let you provide a dependencies array (similar to React’s useEffect):
useRemoteData(() => fetchData(), {
dependencies: [props.userId, otherValue],
});
When the dependency array changes, the store refreshes automatically, and triggerUpdate() will re-fetch if needed.
Each element is compared using Object.is — the same semantics as React's useEffect dependencies.
Since Object.is compares by reference, passing an object or array that gets re-created every render
(like { userId: id } or [id, name] built inline) will cause infinite re-fetches.
Stick to primitive values (strings, numbers, booleans) in the dependencies array.
import { useState } from 'react';
import { useRemoteData, Await } from 'use-remote-data';
let i = 0;
const freshData = (): Promise<number> =>
new Promise((resolve) => {
i += 1;
setTimeout(() => resolve(i), 1000);
});
export function Component() {
const [dep, setDep] = useState(1);
const store = useRemoteData(freshData, { dependencies: [dep] });
return (
<div>
<button onClick={() => setDep(dep + 1)}>Bump dep</button>
<br />
<Await store={store}>
{(num, isStale) => (
<span style={{ color: isStale ? 'darkgray' : 'black' }}>
{num}
</span>
)}
</Await>
</div>
);
}