-
Notifications
You must be signed in to change notification settings - Fork 4
Migrate to TanStack Query for Data Fetching and Caching #27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Conversation
- Refactor useCollections and the closely related useCollection hooks to use TanStack Query for caching and fetching - Improve error propagation, keep original loading states - Update StacApiProvider to manage QueryClient and support custom clients - Clarify peer dependency requirements for @tanstack/react-query in README and docs/react-query-setup.md - Update ESLint config and package.json for new dependencies - Minor fixes to context and tests for compatibility
- Expose QueryClient on window for integration with TanStack Query DevTools (browser extension) - Documented alternative: TanStack Query Devtools floating/embedded component (see https://tanstack.com/query/latest/docs/framework/react/devtools) - Chose browser extension to keep project dependencies clean and offload devtools responsibility to the developer
- Refactor useItem to use TanStack Query for caching and fetching - Improve error propagation, keep original loading states
Adds an ItemDetails component to the example app, showing how to use the useItem hook to fetch and display STAC item details. Improves documentation for consumers of stac-react.
- 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
- Refactor useStacSearch to use TanStack Query for fetching and caching - Replace manual state management with useQuery for search and pagination - Add FetchRequest type to handle both search POST and pagination GET requests - Improve pagination handling to properly extract and manage next/prev links - Clear pagination links only when API changes, not on every new search - Add queryClient.invalidateQueries on API instance change for cache cleanup - Fix type casting in useItem reload function for consistency - Update tests to wrap pagination link assertions in waitFor to prevent race conditions - Maintain backwards compatibility with existing loading states and API
…er initialization order - Add @tanstack/react-query to vite external dependencies to prevent bundling - Refactor StacApiProvider to split into inner/outer components, ensuring QueryClient is available before any React Query hooks execute - Add @tanstack/react-query peer dependency to example app package.json
- Add insertTypesEntry: true to vite-plugin-dts config to generate index.d.ts - Ensures TypeScript can resolve module declarations when package is linked or installed
dzole0311
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@AliceR I gave a first pass through the PR and left a few comments below
- Add centralized query key generators in src/utils/queryKeys.ts - Extract minimal parameters instead of hashing full request objects - Update all hooks to use optimized query key generators Reduces hashing costs for React Query cache lookups by generating smaller, more stable keys with only search-relevant parameters.
- Add enableDevTools prop to StacApiProvider (defaults to false) - Remove automatic DevTools exposure in development mode - Make window.__TANSTACK_QUERY_CLIENT__ optional to prevent type conflicts - Update example app to enable DevTools in development This prevents the library from overwriting QueryClient instances in consuming applications while still allowing opt-in DevTools support.
Clarifies that gcTime (renamed from cacheTime in TanStack Query v5) controls inactive query memory retention and why it's set to 0 in tests.
| const response: Response = await stacApi.getCollections(); | ||
| if (!response.ok) { | ||
| let detail; | ||
| try { | ||
| detail = await response.json(); | ||
| } catch { | ||
| detail = await response.text(); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like all of this handling should be done by a generic fetch function that's reused for all the queries, o that the response is always the same.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure about this suggestion. The error handling is only ~10 lines and it's duplicated in 3 places. IMO the abstraction cost outweighs the benefit:
- Current code is clear - You can see exactly what happens in each hook
- Stack traces are direct - No jumping through utility wrappers
- Easy to customize - If one hook needs different error handling, it's trivial
- Minimal duplication - Only 3 occurrences, not 30
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think that the abstraction will make the code more complicated. Today there are 3 occurrences, but as this gets developed, patterns are copied and we're setting a bad example. It seems that the current approach is to have the api request formulation happen in the api file so it makes sense to move this there.
- Create ApiError class extending Error in src/utils/ApiError.ts - Rename ApiError type to ApiErrorType to avoid naming conflict - Update all hooks to throw new ApiError instances
5a59d65 to
0b4bcdc
Compare
…ient - Remove queryClient prop from StacApiProviderType - Detect parent via QueryClientContext instead of accepting prop - Update docs to show QueryClientProvider wrapping pattern - Document missing options and enableDevTools props in API reference This simplifies the API and prevents duplicate QueryClient instances.
Add tests for StacApiProvider covering QueryClient management, DevTools integration, and context provisioning. - Creates QueryClient when no parent exists - Uses parent QueryClient without nesting providers - DevTools respects enableDevTools prop - Provides stacApi and context methods
BREAKING CHANGE: Remove collections, setCollections, getItem, addItem, deleteItem from context. Context now only provides stacApi. Users should use useCollections() hook directly instead of accessing collections from context. React Query cache is now the single source of truth for data.
… QueryClient" This reverts commit 3ddb6f2.
- Configure a custom QueryClient with specific caching strategies - Pass the queryClient instance to StacApiProvider via prop This change clarifies how to set up and use a custom QueryClient, and investigates the impact of multiple QueryClientProviders on app behavior.
- Update example with staleTime and gcTime, and enableDevTools usage - Document queryClient, options, and enableDevTools props in Component Properties - Fix typo: items.description -> item.description in useItem example - Fix malformed Error type table markdown
BREAKING CHANGE: Hooks no longer return `state` property. Use `isLoading` and `isFetching` booleans instead. - Update hooks to return React Query's isLoading/isFetching directly - Update all tests to check isLoading instead of state - Update example app (Main/index.jsx, ItemDetails.jsx) to use isLoading - Update README with new API documentation Eliminates duplicate state management and provides more granular loading control.
…point
- Add getCollection(collectionId) method to StacApi class
- Refactor useCollection to query /collections/{collectionId} directly
- Add generateCollectionQueryKey for independent collection caching
- Update tests to mock single collection endpoint instead of filtering
Previously, useCollection fetched all collections and filtered to find one.
Now it uses the STAC spec's dedicated endpoint, improving efficiency for
large catalogs and enabling independent collection caching.
- Change reload return type from () => void to () => Promise<QueryObserverResult> - Remove incorrect type casts from refetch in useCollection, useCollections, useItem - Update tests to await reload() calls with proper act() wrapping - Remove eslint-disable comment from useItem test - Remove debounce wrapper from useCollections reload (was returning void) The refetch function from React Query returns a Promise, not void. This fix properly reflects the async nature of reload operations and resolves React act() warnings in tests. Debouncing was removed from useCollections.reload as it's uncommon to debounce explicit reload actions.
BREAKING CHANGE: reload() method renamed to refetch() in useCollection, useCollections, and useItem hooks. - Rename reload() to refetch() in useCollection, useCollections, and useItem - Update all tests to use refetch() instead of reload() - Maintain proper async typing with Promise<QueryObserverResult> Using refetch aligns with React Query's naming convention and makes the API more consistent with the underlying library. The function returns the Promise from React Query's refetch directly. Migration: Replace .reload() with .refetch() in your code.
- Changed dateRangeFrom and dateRangeTo from required to optional in return type - Updated state initialization to use undefined instead of empty strings - Updated setters to accept optional string parameters - Updated reset function to set undefined instead of empty strings This resolves type inconsistencies where the return type claimed required strings but the implementation initialized with empty strings. Conceptually, users should be able to clear/unset date filters by passing undefined.
- Add url field to ApiError class for better debugging context - Add try/catch blocks around all response.json() calls in success paths - Include original error messages in JSON parsing error details - Update ApiErrorType to include optional url field Previously, if a server returned a successful status (200) but invalid JSON (e.g., HTML error pages, malformed responses), the hooks would throw generic parse errors. Now they throw structured ApiError instances with context about what went wrong and which URL failed.
- Add cancel method to debounce utility function with proper TypeScript typing - Add cleanup effect in useStacSearch to cancel pending debounced calls - Prevent orphaned timeouts when component unmounts or _submit function changes Previously, when _submit changed, a new debounced function was created but the old one's timeout wasn't cancelled, causing potential memory leaks and race conditions where stale searches could execute after newer ones.
Close #25
This PR migrates all data fetching hooks (useCollections, useItem, useStacApi, useStacSearch) to use TanStack Query for caching and state management, replacing the previous manual fetch implementation.
Architecture
deleteItem from context. Context now only provides stacApi. Users should
use useCollections() hook directly instead of accessing collections from
context.
stateproperty. UseisLoadingand
isFetchingbooleans instead.useCollections, and useItem hooks.
Documentation
Migration Notes
This change adds @tanstack/react-query as a peer dependency. Consuming applications must install it!
For details, please note the migration guide as well: docs/MIGRATION.md