useCancelablePromise
Track promise status in React with automatic cancellation of stale results when dependencies change.
Hook for working with Promises in React components. It is the state machine behind useExecutionDataView and useInsightDataView, which return the same UseCancelablePromiseState shape.
Tracks promise status (pending / loading / success / error), provides the result or error, supports callbacks, and automatically cancels stale promises when dependencies change.
Basic usage
import type { IAnalyticalBackend } from "@gooddata/sdk-backend-spi";
import { useCancelablePromise } from "@gooddata/sdk-ui";
function CatalogSummary({ backend, workspace }: { backend: IAnalyticalBackend; workspace: string }) {
const { result, error, status } = useCancelablePromise(
{
promise: () => backend.workspace(workspace).catalog().load(),
onSuccess: (catalog) => {
console.log("Catalog loaded", catalog);
},
onError: (err) => {
console.error("Failed to load catalog", err);
},
},
[backend, workspace],
);
if (status === "pending" || status === "loading") {
return <div>Loading...</div>;
}
if (status === "error") {
return <div>Error: {error?.message}</div>;
}
return <div>Loaded {result?.measures().length} measures</div>;
}
Parameters
| Parameter | Type | Description |
|---|---|---|
options.promise | ((signal: AbortSignal) => Promise<TResult>) | undefined | null | Promise factory. When undefined or null, hook stays in "pending" state. |
options.enableAbortController | boolean | Enable AbortController that aborts when dependencies change. The promise must handle the AbortSignal. |
options.onLoading | () => void | Called when promise loading starts. |
options.onPending | () => void | Called when promise is not provided. |
options.onCancel | () => void | Called when dependency list changes before promise resolves. |
options.onSuccess | (result: TResult) => void | Called when promise fulfills. |
options.onError | (err: TError) => void | Called when promise rejects. |
deps | DependencyList | Dependency list that triggers re-execution. |
Return value
UseCancelablePromiseState<TResult, TError> — one of:
{ status: "pending", result: undefined, error: undefined }{ status: "loading", result: undefined, error: undefined }{ status: "success", result: TResult, error: undefined }{ status: "error", result: undefined, error: TError }
States
status | result | error | When |
|---|---|---|---|
"pending" | undefined | undefined | promise is undefined or null. onPending is called. |
"loading" | undefined | undefined | promise is set and has not settled yet, including the first render. onLoading is called when the load starts. |
"success" | TResult | undefined | The promise fulfilled. onSuccess is called with the result. |
"error" | undefined | TError | The promise rejected. onError is called with the rejection value as is; the hook does not convert it. |
When it re-runs
- The effect that calls
promiseusesdepsas its React dependency list. When you passdeps, it runs again only when an item indepschanges by reference (!==). Changes topromiseor to the callbacks alone do not start a new load. - On the render in which
depschange, the hook returns a fresh"loading"(or"pending") state right away, so you never get the previous result together with the new dependencies. - When
depschange or the component unmounts before the promise settles, the hook cancels it and callsonCancel. A canceled promise’s result or error is ignored and does not change the state. - Cancellation only ignores the result. With
enableAbortController: true, the hook also aborts theAbortSignalpassed topromise; the underlying request stops only if your promise honors that signal. - If you omit
deps, React runs the effect after every render, so a new promise starts on each render.
Notes
- The length of
depsmust stay constant between renders. Otherwise the hook throws anUnexpectedSdkError: “The final argument passed to useCancelablePromise changed size between renders.” - The callbacks used for a load are the ones from the render that started it.
TErrordefaults toany. To combine several of these states into one, asuseInsightDataViewdoes, useresolveUseCancelablePromisesStatusandresolveUseCancelablePromisesError.- Don’t use the hook to write data to the backend. It does not cancel the underlying HTTP requests, only ignores stale results, unless
enableAbortControlleris set and your promise honors the signal. Requests can also resolve in any order.
Related
Build custom executions with attributes, measures, filters, sorting, and dimensions via the Analytical Backend fluent API.
Load measures, attributes, and date datasets while your application runs, and turn catalog items into IMeasure and IAttribute objects.
Tell an empty result from a failure, ignore canceled requests, and react to authentication and size limits by narrowing SDK errors with the is* guards instead of matching on message text.
Fetch and accumulate items from a paginated SDK resource, with fetch and reset dependency lists.
Fetch execution data as a DataViewFacade from a prepared execution or inline seriesBy/slicesBy configuration.