Cancellation
Cancel in-flight search requests with an AbortSignal passed on SearchParams. The SDK exposes isAbortError as the canonical way to detect aborted requests.
Installation
pnpm add @media-sdk/core@^0.3.0SearchParams.signal
SearchParams accepts an optional signal: AbortSignal:
interface SearchParams {
query: string;
page?: number;
perPage?: number;
signal?: AbortSignal;
photoFilters?: PhotoSearchFilters;
videoFilters?: VideoSearchFilters;
}signal applies to searchPhotos and searchVideos only. Single-media lookups (getPhoto, getVideo) and getCuratedPhotos do not accept a signal in v0.3.x.
Manual cancellation (core)
import { ApiKeyProvider, PexelsMediaClient } from "@media-sdk/core";
const client = new PexelsMediaClient(
new ApiKeyProvider(process.env.PEXELS_API_KEY!),
);
const controller = new AbortController();
const searchPromise = client.searchPhotos({
query: "nature",
page: 1,
perPage: 20,
signal: controller.signal,
});
// User navigates away — cancel the request
controller.abort();
try {
await searchPromise;
} catch (error) {
// handle abort or other errors
}import { isAbortError } from "@media-sdk/core";
let activeController: AbortController | null = null;
async function search(query: string) {
activeController?.abort();
activeController = new AbortController();
try {
return await client.searchPhotos({
query,
page: 1,
perPage: 20,
signal: activeController.signal,
});
} catch (error) {
if (isAbortError(error)) {
return null; // superseded by a newer search
}
throw error;
}
}isAbortError
Import isAbortError from @media-sdk/core — do not rely on message strings:
import { isAbortError, MediaError } from "@media-sdk/core";
try {
await client.searchPhotos({
query: "ocean",
signal: controller.signal,
});
} catch (error) {
if (isAbortError(error)) {
return; // expected — request was cancelled
}
if (error instanceof MediaError) {
console.error(error.code, error.status);
return;
}
throw error;
}isAbortError returns true for DOMException or Error instances with name === "AbortError".
Cache and deduplication behavior
When a signaled request is aborted:
- The in-flight request rejects with an abort error
- Aborted responses are not cached
- Signaled requests are not deduplicated with unsigned in-flight requests for the same cache key
This prevents stale aborted results from being served to later callers.
React hook auto-abort
useMediaSearch and useMediaVideos from @media-sdk/react@^0.3.0 automatically pass an AbortSignal and abort when:
- The query, page, or perPage changes (a new search starts)
refetch()is called while a request is active- The component unmounts
Aborted requests are silently ignored in hook state:
errorstaysnull(aborts are not surfaced as errors)- Stale responses cannot overwrite newer results (request-id guard)
import { useState } from "react";
import { MediaProvider, useMediaSearch } from "@media-sdk/react";
import { PexelsMediaClient, ApiKeyProvider } from "@media-sdk/core";
const client = new PexelsMediaClient(
new ApiKeyProvider(import.meta.env.VITE_PEXELS_API_KEY),
);
function SearchInput() {
const [query, setQuery] = useState("");
const { data, loading, error } = useMediaSearch({
query,
page: 1,
perPage: 20,
enabled: query.length > 0,
});
// Changing query aborts the previous in-flight search automatically
return (
<>
<input
value={query}
onChange={(e) => setQuery(e.target.value)}
/>
{loading && <p>Loading…</p>}
{error && <p>Error: {error.message}</p>}
{data && <p>{data.items.length} photos</p>}
</>
);
}
function SearchApp() {
return (
<MediaProvider client={client}>
<SearchInput />
</MediaProvider>
);
}For manual core usage outside React, replicate the pattern with your own AbortController lifecycle.
Related pages
- MediaClient —
SearchParams - Errors — abort vs
MediaError - React hooks — hook cancellation behavior