Skip to content

Commit 99d326e

Browse files
committed
feat: Refactor, use context API
1 parent 877d418 commit 99d326e

File tree

13 files changed

+363
-141
lines changed

13 files changed

+363
-141
lines changed

example/src/App.js

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
1+
import { StacApiProvider } from "stac-react";
12
import Header from "./layout/Header";
23
import Main from "./pages/Main";
34

45
function App() {
56
return (
6-
<div className="App grid grid-rows-[min-content_1fr]">
7-
<Header />
8-
<main className="flex items-stretch">
9-
<Main />
10-
</main>
11-
</div>
7+
<StacApiProvider apiUrl={process.env.REACT_APP_STAC_API}>
8+
<div className="App grid grid-rows-[min-content_1fr]">
9+
<Header />
10+
<main className="flex items-stretch">
11+
<Main />
12+
</main>
13+
</div>
14+
</StacApiProvider>
1215
);
1316
}
1417

example/src/pages/Main/QueryBuilder.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ QueryBuilder.propTypes = {
7676
}
7777

7878
QueryBuilder.defaultProps = {
79-
collections: []
79+
collections: {}
8080
}
8181

8282
export default QueryBuilder;

example/src/pages/Main/index.jsx

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useCallback, useState } from "react";
2-
import { useStacSearch, useCollections, useStacApi } from "stac-react";
2+
import { useStacSearch, useCollections, useStacApi, StacApiProvider } from "stac-react";
33

44
import ItemList from "./ItemList";
55
import Map from "./Map";
@@ -13,10 +13,7 @@ const options = {
1313

1414
function Main() {
1515
const [isBboxDrawEnabled, setIsBboxDrawEnabled] = useState(false);
16-
const { stacApi } = useStacApi(process.env.REACT_APP_STAC_API, options);
17-
18-
const { collections } = useCollections(stacApi);
19-
16+
const { collections } = useCollections();
2017
const {
2118
setBbox,
2219
collections: selectedCollections,
@@ -31,7 +28,7 @@ function Main() {
3128
error,
3229
nextPage,
3330
previousPage
34-
} = useStacSearch(stacApi);
31+
} = useStacSearch();
3532

3633
const handleDrawComplete = useCallback((feature) => {
3734
setIsBboxDrawEnabled(false);

jest.config.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ module.exports = {
44
testEnvironment: 'jsdom',
55
setupFilesAfterEnv: ['./jest.setup.ts'],
66
testMatch: [
7-
'**/*.test.ts'
7+
'**/*.test.ts',
8+
'**/*.test.tsx'
89
]
9-
};
10+
};

rollup.config.mjs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ export default [
1212
format: "es",
1313
sourcemap,
1414
},
15-
plugins: [typescript()],
15+
plugins: [
16+
typescript({ exclude: ["**/*.test.ts"] })
17+
],
1618
},
1719
{
1820
input,
@@ -29,6 +31,8 @@ export default [
2931
format: "cjs",
3032
sourcemap,
3133
},
32-
plugins: [typescript()],
34+
plugins: [
35+
typescript({ exclude: ["**/*.test.ts"] })
36+
],
3337
},
3438
];

src/context/index.tsx

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import React, { useMemo, useContext, useState } from 'react';
2+
import { createContext } from 'react';
3+
4+
import StacApi from '../stac-api';
5+
import useStacApi from '../hooks/useStacApi';
6+
import type { CollectionsResponse } from '../types/stac';
7+
8+
type StacApiContextType = {
9+
stacApi?: StacApi;
10+
collections?: CollectionsResponse;
11+
setCollections: (collections?: CollectionsResponse) => void;
12+
}
13+
14+
type StacApiProviderType = {
15+
apiUrl: string;
16+
children: React.ReactNode
17+
}
18+
19+
export const StacApiContext = createContext<StacApiContextType>({} as StacApiContextType);
20+
21+
export function StacApiProvider({ children, apiUrl }: StacApiProviderType) {
22+
const { stacApi } = useStacApi(apiUrl);
23+
const [ collections, setCollections ] = useState<CollectionsResponse>();
24+
25+
const contextValue = useMemo(() => ({
26+
stacApi,
27+
collections,
28+
setCollections
29+
}), [collections, stacApi]);
30+
31+
return (
32+
<StacApiContext.Provider value={contextValue}>
33+
{ children }
34+
</StacApiContext.Provider>
35+
);
36+
}
37+
38+
export function useStacApiContext() {
39+
const { stacApi, collections, setCollections } = useContext(StacApiContext);
40+
41+
return {
42+
stacApi,
43+
collections,
44+
setCollections
45+
};
46+
}

src/hooks/useCollections.test.ts

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,44 @@
11
import fetch from 'jest-fetch-mock';
22
import { renderHook, act } from '@testing-library/react-hooks';
33
import useCollections from './useCollections';
4-
import StacApi, { SearchMode } from '../stac-api';
4+
import wrapper from './wrapper';
55

66
describe('useCollections', () => {
7-
fetch.mockResponseOnce(JSON.stringify({ links: [] }));
8-
const stacApi = new StacApi('https://fake-stac-api.net', SearchMode.POST);
9-
beforeEach(() => fetch.resetMocks());
7+
beforeEach(() => {
8+
fetch.resetMocks();
9+
});
1010

1111
it('queries collections', async () => {
12-
fetch.mockResponseOnce(JSON.stringify({ data: '12345' }));
12+
fetch
13+
.mockResponseOnce(JSON.stringify({ links: [] }), { url: 'https://fake-stac-api.net' })
14+
.mockResponseOnce(JSON.stringify({ data: '12345' }));
15+
1316
const { result, waitForNextUpdate } = renderHook(
14-
() => useCollections(stacApi)
17+
() => useCollections(),
18+
{ wrapper }
1519
);
1620
await waitForNextUpdate();
17-
expect(fetch.mock.calls[0][0]).toEqual('https://fake-stac-api.net/collections');
21+
await waitForNextUpdate();
22+
expect(fetch.mock.calls[1][0]).toEqual('https://fake-stac-api.net/collections');
1823
expect(result.current.collections).toEqual({ data: '12345' });
1924
expect(result.current.state).toEqual('IDLE');
2025
});
2126

2227
it('reloads collections', async () => {
23-
fetch.mockResponseOnce(JSON.stringify({ data: 'original' }));
28+
fetch
29+
.mockResponseOnce(JSON.stringify({ links: [] }), { url: 'https://fake-stac-api.net' })
30+
.mockResponseOnce(JSON.stringify({ data: 'original' }))
31+
.mockResponseOnce(JSON.stringify({ data: 'reloaded' }));
32+
2433
const { result, waitForNextUpdate } = renderHook(
25-
() => useCollections(stacApi)
34+
() => useCollections(),
35+
{ wrapper }
2636
);
2737
await waitForNextUpdate();
38+
await waitForNextUpdate();
2839
expect(result.current.collections).toEqual({ data: 'original' });
2940

3041
expect(result.current.state).toEqual('IDLE');
31-
fetch.mockResponseOnce(JSON.stringify({ data: 'reloaded' }));
3242
act(() => result.current.reload());
3343
await waitForNextUpdate();
3444
expect(result.current.collections).toEqual({ data: 'reloaded' });

src/hooks/useCollections.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
import { useCallback, useEffect, useState, useMemo } from 'react';
2-
import StacApi from '../stac-api';
32
import type { LoadingState } from '../types';
43
import type { CollectionsResponse } from '../types/stac';
54
import debounce from '../utils/debounce';
5+
import { useStacApiContext } from '../context';
66

77
type StacCollectionsHook = {
88
collections?: CollectionsResponse,
99
reload: () => void,
1010
state: LoadingState
1111
};
1212

13-
function useCollections(stacApi?: StacApi): StacCollectionsHook {
14-
const [ collections, setCollections ] = useState<CollectionsResponse>();
13+
function useCollections(): StacCollectionsHook {
14+
const { stacApi, collections, setCollections } = useStacApiContext();
1515
const [ state, setState ] = useState<LoadingState>('IDLE');
1616

1717
const _getCollections = useCallback(
@@ -26,11 +26,18 @@ function useCollections(stacApi?: StacApi): StacCollectionsHook {
2626
.finally(() => setState('IDLE'));
2727
}
2828
},
29-
[stacApi]
29+
[setCollections, stacApi]
3030
);
3131
const getCollections = useMemo(() => debounce(_getCollections), [_getCollections]);
3232

33-
useEffect(() => getCollections(), [getCollections]);
33+
useEffect(
34+
() => {
35+
if (stacApi && !collections) {
36+
getCollections();
37+
}
38+
},
39+
[getCollections, stacApi, collections]
40+
);
3441

3542
return {
3643
collections,

src/hooks/useStacApi.test.ts

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,35 @@
11
import fetch from 'jest-fetch-mock';
22
import { renderHook } from '@testing-library/react-hooks';
3-
import useStacApi from './useStacApi';
43
import useCollections from './useCollections';
4+
import wrapper from './wrapper';
55

66
describe('useStacApi', () => {
77
beforeEach(() => fetch.resetMocks());
8-
98
it('initilises StacAPI', async () => {
10-
fetch.mockResponseOnce(JSON.stringify({ links: [] }), { url: 'https://fake-stac-api.net' });
11-
const { result: stacApiResult, waitForNextUpdate: waitForApiUpdate } = renderHook(
12-
() => useStacApi('https://fake-stac-api.net')
13-
);
14-
await waitForApiUpdate();
9+
fetch
10+
.mockResponseOnce(JSON.stringify({ links: [] }), { url: 'https://fake-stac-api.net' })
11+
.mockResponseOnce(JSON.stringify({ data: '12345' }));
1512

16-
fetch.mockResponseOnce(JSON.stringify({ data: '12345' }));
17-
const { waitForNextUpdate: waitForCollectionsUpdate } = renderHook(
18-
() => useCollections(stacApiResult.current.stacApi)
13+
const { waitForNextUpdate } = renderHook(
14+
() => useCollections(),
15+
{ wrapper }
1916
);
20-
await waitForCollectionsUpdate();
17+
await waitForNextUpdate();
18+
await waitForNextUpdate();
2119
expect(fetch.mock.calls[1][0]).toEqual('https://fake-stac-api.net/collections');
2220
});
2321

2422
it('initilises StacAPI with redirect URL', async () => {
25-
fetch.mockResponseOnce(JSON.stringify({ links: [] }), { url: 'https://fake-stac-api.net/redirect/' });
26-
const { result: stacApiResult, waitForNextUpdate: waitForApiUpdate } = renderHook(
27-
() => useStacApi('https://fake-stac-api.net')
28-
);
29-
await waitForApiUpdate();
23+
fetch
24+
.mockResponseOnce(JSON.stringify({ links: [] }), { url: 'https://fake-stac-api.net/redirect/' })
25+
.mockResponseOnce(JSON.stringify({ data: '12345' }));
3026

31-
fetch.mockResponseOnce(JSON.stringify({ data: '12345' }));
32-
const { waitForNextUpdate: waitForCollectionsUpdate } = renderHook(
33-
() => useCollections(stacApiResult.current.stacApi)
27+
const { waitForNextUpdate } = renderHook(
28+
() => useCollections(),
29+
{ wrapper }
3430
);
35-
await waitForCollectionsUpdate();
31+
await waitForNextUpdate();
32+
await waitForNextUpdate();
3633
expect(fetch.mock.calls[1][0]).toEqual('https://fake-stac-api.net/redirect/collections');
3734
});
3835
});

0 commit comments

Comments
 (0)