Skip to content

Commit 9999717

Browse files
committed
feat: migrate useStacApi hook to TanStack Query
- Refactor useStacApi to use TanStack Query for fetching and caching - Add QueryClientProvider to wrapper to ensure a clean instance for every test - Refactor useStacSearch.test.ts to use setupStacSearch helper for all tests, adding a step to wait for IDLE stacApi
1 parent 3013303 commit 9999717

File tree

5 files changed

+235
-344
lines changed

5 files changed

+235
-344
lines changed

src/hooks/useCollections.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ function useCollections(): StacCollectionsHook {
5151
});
5252

5353
// Sync collections with context
54-
// This preserves the previous logic for consumers and tests
5554
useEffect(() => {
5655
if (collections) {
5756
setCollections(collections);
@@ -63,13 +62,14 @@ function useCollections(): StacCollectionsHook {
6362
const reload = useMemo(() => debounce(refetch), [refetch]);
6463

6564
useEffect(() => {
66-
// Map TanStack Query loading states to previous LoadingState type
67-
if (isLoading || isFetching) {
65+
if (!stacApi) {
66+
setState('IDLE');
67+
} else if (isLoading || isFetching) {
6868
setState('LOADING');
6969
} else {
7070
setState('IDLE');
7171
}
72-
}, [isLoading, isFetching]);
72+
}, [stacApi, isLoading, isFetching]);
7373

7474
return {
7575
collections,

src/hooks/useStacApi.ts

Lines changed: 25 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,38 @@
1-
import { useEffect, useState } from 'react';
1+
import { useQuery } from '@tanstack/react-query';
22
import StacApi, { SearchMode } from '../stac-api';
33
import { Link } from '../types/stac';
44
import { GenericObject } from '../types';
55

66
type StacApiHook = {
77
stacApi?: StacApi;
8+
isLoading: boolean;
9+
isError: boolean;
810
};
911

1012
function useStacApi(url: string, options?: GenericObject): StacApiHook {
11-
const [stacApi, setStacApi] = useState<StacApi>();
12-
13-
useEffect(() => {
14-
let baseUrl: string;
15-
let searchMode = SearchMode.GET;
16-
17-
fetch(url, {
18-
headers: {
19-
'Content-Type': 'application/json',
20-
...options?.headers,
21-
},
22-
})
23-
.then((response) => {
24-
baseUrl = response.url;
25-
return response;
26-
})
27-
.then((response) => response.json())
28-
.then((response) => {
29-
const doesPost = response.links.find(
30-
({ rel, method }: Link) => rel === 'search' && method === 'POST'
31-
);
32-
if (doesPost) {
33-
searchMode = SearchMode.POST;
34-
}
35-
})
36-
.then(() => setStacApi(new StacApi(baseUrl, searchMode, options)))
37-
.catch((e) => {
38-
// eslint-disable-next-line no-console
39-
console.error('Failed to initialize StacApi:', e);
13+
const { data, isSuccess, isLoading, isError } = useQuery({
14+
queryKey: ['stacApi', url, options],
15+
queryFn: async () => {
16+
let searchMode = SearchMode.GET;
17+
const response = await fetch(url, {
18+
headers: {
19+
'Content-Type': 'application/json',
20+
...options?.headers,
21+
},
4022
});
41-
}, [url, options]);
42-
43-
return { stacApi };
23+
const baseUrl = response.url;
24+
const json = await response.json();
25+
const doesPost = json.links?.find(
26+
({ rel, method }: Link) => rel === 'search' && method === 'POST'
27+
);
28+
if (doesPost) {
29+
searchMode = SearchMode.POST;
30+
}
31+
return new StacApi(baseUrl, searchMode, options);
32+
},
33+
staleTime: Infinity,
34+
});
35+
return { stacApi: isSuccess ? data : undefined, isLoading, isError };
4436
}
4537

4638
export default useStacApi;

0 commit comments

Comments
 (0)