React hooks to build front-end applications for STAC APIs.
Note: stac-react is in early development, the API will likely break in future versions.
With NPM:
npm i @developmentseed/stac-reactWith Yarn:
yarn add @developmentseed/stac-reactstac-react relies on TanStack Query for data fetching and caching. To avoid duplicate React Query clients and potential version conflicts, stac-react lists @tanstack/react-query as a peer dependency. This means you must install it in your project:
npm install @tanstack/react-query
# or
yarn add @tanstack/react-queryIf you do not install it, your package manager will warn you, and stac-react will not work correctly.
stac-react's hooks must be used inside children of a React context that provides access to the stac-react's core functionality.
To get started, initialize StacApiProvider with the base URL of the STAC catalog. StacApiProvider automatically sets up a TanStack Query QueryClientProvider for you, so you do not need to wrap your app with QueryClientProvider yourself.
import { StacApiProvider } from 'stac-react';
function StacApp() {
return (
<StacApiProvider apiUrl="https://my-stac-api.com">{/* Other components */}</StacApiProvider>
);
}If you want to provide your own custom QueryClient (for advanced caching or devtools), you can pass it as a prop:
import { StacApiProvider } from 'stac-react';
import { QueryClient } from '@tanstack/react-query';
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 5 * 60 * 1000, // 5 minutes
gcTime: 10 * 60 * 1000, // 10 minutes
},
},
});
function StacApp() {
const isDevelopment = process.env.NODE_ENV === 'development';
return (
<StacApiProvider
apiUrl="https://my-stac-api.com"
queryClient={queryClient}
enableDevTools={isDevelopment}
>
{/* Other components */}
</StacApiProvider>
);
}For additional information, see the React Query setup guide: docs/react-query-setup.md.
Now you can start using stac-react hooks in child components of StacApiProvider
import { StacApiProvider, useCollections } from 'stac-react';
function Collections() {
const { collections } = useCollections();
return (
<ul>
{collections.collections.map(({ id, title }) => (
<li key={id}>{title}</li>
))}
</ul>
);
}
function StacApp() {
return (
<StacApiProvider apiUrl="https://my-stac-api.com">
<Collections />
</StacApiProvider>
);
}Provides the React context required for stac-react hooks.
import { StacApiProvider } from 'stac-react';
function StacApp() {
return <StacApiProvider apiUrl="https://my-stac-api.com">// Other components</StacApiProvider>;
}| Option | Type | Description |
|---|---|---|
apiUrl |
string |
The base URL of the STAC catalog. |
queryClient |
QueryClient |
Optional. Custom TanStack Query QueryClient instance. If not provided, a default QueryClient will be created. |
options |
object |
Optional. Configuration object for customizing STAC API requests (e.g., headers, authentication). |
enableDevTools |
boolean |
Optional. Enables TanStack Query DevTools browser extension integration by exposing the QueryClient on window.__TANSTACK_QUERY_CLIENT__. Defaults to false. Recommended for development only. |
Retrieves collections from a STAC catalog.
import { useCollections } from 'stac-react';
const { collections } = useCollections();| Option | Type | Description |
|---|---|---|
collections |
array |
A list of collections available from the STAC catalog. Is null if collections have not been retrieved. |
isLoading |
boolean |
true when the initial request is in progress. false once data is loaded or an error occurred. |
isFetching |
boolean |
true when any request is in progress (including background refetches). false otherwise. |
reload |
function |
Callback function to trigger a reload of collections. |
error |
Error |
Error information if the last request was unsuccessful. undefined if the last request was successful. |
import { useCollections } from "stac-react";
function CollectionList() {
const { collections, isLoading } = useCollections();
if (isLoading) {
return <p>Loading collections...</p>
}
return (
<>
{collections ? (
<ul>
{collections.collections.map(({ id, title }) => (
<li key={id}>{title}</li>
))}
</ul>
<button type="button" onclick={reload}>Update collections</button>
): (
<p>No collections</p>
)}
</>
);
}Retrieves a single collection from the STAC catalog.
import { useCollection } from 'stac-react';
const { collection } = useCollection(id);| Option | Type | Description |
|---|---|---|
id |
string |
The collection ID. |
| Option | Type | Description |
|---|---|---|
collection |
object |
The collection matching the provided ID. Is null if collection has not been retrieved. |
isLoading |
boolean |
true when the initial request is in progress. false once data is loaded or an error occurred. |
isFetching |
boolean |
true when any request is in progress (including background refetches). false otherwise. |
reload |
function |
Callback function to trigger a reload of the collection. |
error |
Error |
Error information if the last request was unsuccessful. undefined if the last request was successful. |
import { useCollection } from 'stac-react';
function Collection() {
const { collection, isLoading } = useCollection('collection_id');
if (isLoading) {
return <p>Loading collection...</p>;
}
return (
<>
{collection ? (
<>
<h2>{collection.id}</h2>
<p>{collection.description}</p>
</>
) : (
<p>Not found</p>
)}
</>
);
}Retrieves an item from the STAC catalog. To retrieve an item, provide its full url to the useItem hook.
import { useItem } from 'stac-react';
const { item } = useItem(url);| Option | Type | Description |
|---|---|---|
url |
string |
The URL of the item you want to retrieve. |
| Option | Type | Description |
|---|---|---|
item |
object |
The item matching the provided URL. |
isLoading |
boolean |
true when the initial request is in progress. false once data is loaded or an error occurred. |
isFetching |
boolean |
true when any request is in progress (including background refetches). false otherwise. |
reload |
function |
Callback function to trigger a reload of the item. |
error |
Error |
Error information if the last request was unsuccessful. undefined if the last request was successful. |
import { useItem } from 'stac-react';
function Item() {
const { item, isLoading } = useItem('https://stac-catalog.com/items/abc123');
if (isLoading) {
return <p>Loading item...</p>;
}
return (
<>
{item ? (
<>
<h2>{item.id}</h2>
<p>{item.description}</p>
</>
) : (
<p>Not found</p>
)}
</>
);
}Executes a search against a STAC API using the provided search parameters.
import { useStacSearch } from 'stac-react';
const { results } = useStacSearch();| Option | Type | Description |
| ------------------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------- |
| submit | function | Callback to submit the search using the current filter parameters. Excecutes an API call to the specified STAC API. |
| ids | array<string> | List of item IDs to match in the search, undefined if unset. |
| setIds(itemIds) | function | Callback to set ids. itemIds must be an array of string with the IDs of the selected items, or undefined to reset. |
| bbox | array<number> | Array of coordinates [northWestLon, northWestLat, southEastLon, southEastLat], undefined if unset. |
| setBbox(bbox) | function | Callback to set bbox. bbox must be an array of coordinates [northWestLon, northWestLat, southEastLon, southEastLat], or undefined to reset. |
| collections | array<string> | List of select collection IDs included in the search query. undefined if unset. |
| setCollections(collectionIDs) | function | Callback to set collections. collectionIDs must be an array of string with the IDs of the selected collections, or undefined to reset. |
| dateRangeFrom | string | The from-date of the search query. undefined if unset. |
| setDateRangeFrom(fromDate) | function | Callback to set dateRangeFrom. fromDate must be ISO representation of a date, ie. 2022-05-18, or undefined to reset. |
| dateRangeTo | string | The to-date of the search query. undefined if unset. |
| setDateRangeTo(toDate) | function | Callback to set dateRangeto. toDate must be ISO representation of a date, ie. 2022-05-18, or undefined to reset. |
| sortby | array | Specifies the order of results. Array of { field: string, direction: 'asc' | 'desc' } |
| setSortby(sort) | function | Callback to set sortby. sort must be an array of { field: string, direction: 'asc' | 'desc' }, or undefined to reset. |
| limit | number | The number of results returned per result page. |
| setLimit(limit) | function | Callback to set limit. limit must be a number, or undefined to reset. |
| results | object | The result of the last search query; a GeoJSON FeatureCollection with additional members. undefined if the search request has not been submitted, or if there was an error. |
| isLoading | boolean | true when the initial request is in progress. false once data is loaded or an error occurred. |
| isFetching | boolean | true when any request is in progress (including background refetches and pagination). false otherwise. |
| error | Error | Error information if the last request was unsuccessful. undefined if the last request was successful. |
| nextPage | function | Callback function to load the next page of results. Is undefined if the last page is the currently loaded. |
| previousPage | function | Callback function to load the previous page of results. Is undefined if the first page is the currently loaded. |
import { useStacSearch } from 'stac-react';
function StacComponent() {
const { result } = useStacSearch();
return (
<>
<div class="item-list">
{results && (
<ul>
{results.features.map(({ id }) => (
<li key={id}>{id}</li>
))}
</ul>
)}
</div>
</>
);
}import { useCallback } from 'react';
import { useStacSearch } from 'stac-react';
import Map from './map';
function StacComponent() {
const { error, result } = useStacSearch();
return (
<>
<div class="item-list">
{error && <p>{error.detail}</p>}
{results && (
<ul>
{results.features.map(({ id }) => (
<li key={id}>{id}</li>
))}
</ul>
)}
</div>
</>
);
}import { useStacSearch } from "stac-react";
function StacComponent() {
const {
nextPage,
previousPage,
result
} = useStacSearch();
return (
<>
<div class="item-list">
{results && (
// render results
)}
</div>
<div class="pagination">
<button type="button" disabled={!previousPage} onClick={previousPage}>
<button type="button" disabled={!nextPage} onClick={nextPage}>
</div>
</>
)
}import { useStacSearch } from "stac-react";
function StacComponent() {
const { collections } = useCollections();
const { collections: selectedCollections, setCollections, results, submit } = useStacSearch();
const handleChange = useCallback((event) => {
const { value } = event.target;
const nextValues = selectedCollections.includes(value)
? selectedCollections.filter((v) => v !== value)
: [ ...selectedCollections, value ];
setCollections(nextValues);
}, [selectedCollections, setCollections]);
return (
<>
<div class="query-builder">
<form onSubmit={submit}>
<fieldset>
<legend>Select collections</legend>
{collections.map(({ id, title }) => (
<input
id={id}
name="collections"
value={id}
type="checkbox"
onChange={handleChange}
checked={selectedCollections.includes(id)}
/>
<label htmlFor={id}>{title}</label>
))}
<fieldset>
<button type="submit">Search</button>
</form>
</div>
</>
)
}import { useCallback } from 'react';
import { useStacSearch } from 'stac-react';
function StacComponent() {
const { bbox, setBbox, submit } = useStacSearch();
const handleDrawComplete = useCallback(
(feature) => {
setIsBboxDrawEnabled(false);
const { coordinates } = feature.geometry;
const bbox = [...coordinates[0][0], ...coordinates[0][2]];
setBbox(bbox);
},
[setBbox]
);
<Map handleDrawComplete={handleDrawComplete} />;
}This example assumes that a Map component handles drawing and calls handleDrawComplete to set the bbox for the search. handleDrawComplete is called with a GeoJSON feature representing the bounding box drawn on the map.
import { useStacSearch } from "stac-react";
function StacComponent() {
const {
dateRangeFrom,
setDateRangeFrom,
dateRangeTo,
setDateRangeTo,
submit
} = useStacSearch();
return (
<>
<input type="date" name="date_from" onChange={setDateRangeFrom} value={dateRangeFrom} />
<input type="date" name="date_to" onChange={setDateRangeTo} value={dateRangeTo} />
<button type="button" onclick={submit}>
</>
)
}{
detail: "Invalid bbox object"
status: 400,
statusText: "Bad Request"
}| Option | Type | Description |
|---|---|---|
detail |
string | object |
The error returned from the API. Either a string or an object depending on the response. |
status |
number |
HTTP status code of the response. |
statusText |
string |
Status text for the response. |
Run tests
yarn testLint
yarn lintBuild
yarn build