Skip to content

Commit a04443b

Browse files
committed
feat: migrate useItem hook to TanStack Query
- Refactor useItem to use TanStack Query for caching and fetching - Improve error propagation, keep original loading states
1 parent e40fcce commit a04443b

File tree

2 files changed

+46
-58
lines changed

2 files changed

+46
-58
lines changed

src/hooks/useItem.test.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,10 @@ describe('useItem', () => {
6868
});
6969
await waitFor(() => expect(result.current.item).toEqual({ id: 'abc' }));
7070

71-
act(() => result.current.reload());
71+
await act(async () => {
72+
// eslint-disable-next-line @typescript-eslint/await-thenable
73+
await result.current.reload();
74+
});
7275

7376
await waitFor(() => expect(result.current.item).toEqual({ id: 'abc', description: 'Updated' }));
7477
});

src/hooks/useItem.ts

Lines changed: 42 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { useState, useEffect, useCallback } from 'react';
1+
import { useEffect, useState } from 'react';
2+
import { useQuery } from '@tanstack/react-query';
23
import { Item } from '../types/stac';
34
import { ApiError, LoadingState } from '../types';
45
import { useStacApiContext } from '../context/useStacApiContext';
@@ -11,71 +12,55 @@ type ItemHook = {
1112
};
1213

1314
function useItem(url: string): ItemHook {
14-
const { stacApi, getItem, addItem, deleteItem } = useStacApiContext();
15+
const { stacApi } = useStacApiContext();
1516
const [state, setState] = useState<LoadingState>('IDLE');
16-
const [item, setItem] = useState<Item>();
17-
const [error, setError] = useState<ApiError>();
1817

19-
useEffect(() => {
20-
if (!stacApi) return;
21-
22-
setState('LOADING');
23-
new Promise((resolve, reject) => {
24-
const i = getItem(url);
25-
if (i) {
26-
resolve(i);
27-
} else {
28-
stacApi
29-
.fetch(url)
30-
.then((r: Response) => r.json())
31-
.then((r: Item) => {
32-
addItem(url, r);
33-
resolve(r);
34-
})
35-
// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors
36-
.catch((err: unknown) => reject(err));
18+
const fetchItem = async (): Promise<Item> => {
19+
if (!stacApi) throw new Error('No STAC API configured');
20+
const response: Response = await stacApi.get(url);
21+
if (!response.ok) {
22+
let detail;
23+
try {
24+
detail = await response.json();
25+
} catch {
26+
detail = await response.text();
3727
}
38-
})
39-
.then(setItem)
40-
.catch((err: unknown) => setError(err as ApiError))
41-
.finally(() => setState('IDLE'));
42-
}, [stacApi, addItem, getItem, url]);
43-
44-
const fetchItem = useCallback(() => {
45-
if (!stacApi) return;
28+
const err = Object.assign(new Error(response.statusText), {
29+
status: response.status,
30+
statusText: response.statusText,
31+
detail,
32+
});
33+
throw err;
34+
}
35+
return await response.json();
36+
};
4637

47-
setState('LOADING');
48-
new Promise((resolve, reject) => {
49-
const i = getItem(url);
50-
if (i) {
51-
resolve(i);
52-
} else {
53-
stacApi
54-
.fetch(url)
55-
.then((r: Response) => r.json())
56-
.then((r: Item) => {
57-
addItem(url, r);
58-
resolve(r);
59-
})
60-
// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors
61-
.catch((err: unknown) => reject(err));
62-
}
63-
})
64-
.then(setItem)
65-
.catch((err: unknown) => setError(err as ApiError))
66-
.finally(() => setState('IDLE'));
67-
}, [addItem, getItem, stacApi, url]);
38+
const {
39+
data: item,
40+
error,
41+
isLoading,
42+
isFetching,
43+
refetch,
44+
} = useQuery<Item, ApiError>({
45+
queryKey: ['item', url],
46+
queryFn: fetchItem,
47+
enabled: !!stacApi,
48+
retry: false,
49+
});
6850

69-
const reload = useCallback(() => {
70-
deleteItem(url);
71-
fetchItem();
72-
}, [deleteItem, fetchItem, url]);
51+
useEffect(() => {
52+
if (isLoading || isFetching) {
53+
setState('LOADING');
54+
} else {
55+
setState('IDLE');
56+
}
57+
}, [isLoading, isFetching]);
7358

7459
return {
7560
item,
7661
state,
77-
error,
78-
reload,
62+
error: error as ApiError,
63+
reload: refetch,
7964
};
8065
}
8166

0 commit comments

Comments
 (0)