Skip to content

Add Standalone Hooks (Context-Free Mode) #34

@AliceR

Description

@AliceR

Problem

Currently, all stac-react hooks require the StacApiProvider context to function. This limits the library's flexibility when working with:

  • Static STAC catalogs without a formal API
  • Direct URL-based STAC resource fetching
  • Multiple STAC sources in the same application
  • File-based or uploaded STAC JSON

Projects like stac-map need to fetch arbitrary STAC resources by URL without committing to a single API endpoint via context.

Current Behavior

// This requires StacApiProvider wrapping the component
import { useCollection, useItem } from '@developmentseed/stac-react';

function MyComponent() {
  const { collection } = useCollection('my-collection-id'); // Requires context
  const { item } = useItem(url); // Requires context
}

// Must be wrapped:
<StacApiProvider apiUrl="https://api.example.com">
  <MyComponent />
</StacApiProvider>

Desired Behavior

// Make context optional
import { useItem } from '@developmentseed/stac-react';

function MyComponent() {
  // Works without StacApiProvider when full URL provided
  const { item } = useItem('https://example.com/items/item-id.json');
}

Proposed Solution

1. Add Context-Free Variants

Create standalone versions of hooks that don't require StacApiProvider:

  • useStacResource(url) - Generic hook for any STAC resource
  • useStacCollection(url) - Fetch collection by URL
  • useStacItem(url) - Fetch item by URL
  • useStacCatalog(url) - Fetch catalog by URL

2. Make Existing Hooks Context-Aware

Modify existing hooks to detect whether they're inside a context:

function useCollection(collectionIdOrUrl: string) {
  const context = useStacApiContext();
  
  if (context?.stacApi) {
    // Use API-centric approach (current behavior)
    return useApiCollection(collectionIdOrUrl);
  } else if (isFullUrl(collectionIdOrUrl)) {
    // Use standalone approach
    return useStandaloneCollection(collectionIdOrUrl);
  } else {
    throw new Error('Either provide StacApiProvider context or use full URLs');
  }
}

3. Export Standalone Variants Separately

// src/standalone/index.ts
export { useStacResource } from './useStacResource';
export { useStacCollection } from './useStacCollection';
export { useStacItem } from './useStacItem';

Implementation Details

New Hook: useStacResource

import { useQuery } from '@tanstack/react-query';

type StacResourceHook = {
  data?: StacCatalog | StacCollection | StacItem;
  isLoading: boolean;
  isFetching: boolean;
  error?: Error;
  refetch: () => void;
};

function useStacResource(url: string, options?: RequestInit): StacResourceHook {
  const { data, error, isLoading, isFetching, refetch } = useQuery({
    queryKey: ['stac-resource', url],
    queryFn: async () => {
      const response = await fetch(url, {
        headers: {
          'Content-Type': 'application/json',
          ...options?.headers,
        },
        ...options,
      });
      
      if (!response.ok) {
        throw new Error(`Failed to fetch STAC resource: ${response.statusText}`);
      }
      
      return response.json();
    },
    enabled: !!url,
    retry: false,
  });

  return { data, error, isLoading, isFetching, refetch };
}

Benefits

  • ✅ Use stac-react without requiring an API provider
  • ✅ Fetch STAC resources from any URL
  • ✅ Support static catalogs and file-based STAC
  • ✅ Enable multi-source STAC applications
  • ✅ Maintain backward compatibility with existing API-centric approach
  • ✅ Align with how stac-map and other tools work with STAC

Breaking Changes

None - this is additive functionality. Existing API-centric hooks remain unchanged.

Testing Requirements

  • Test hooks work without StacApiProvider
  • Test hooks work with full URLs
  • Test error handling for invalid URLs
  • Test that existing API-centric behavior is unchanged
  • Test with various STAC resource types (catalog, collection, item)

Documentation Requirements

  • Add examples for context-free usage
  • Document when to use API-centric vs standalone approach
  • Update README with standalone examples
  • Add migration guide for projects using direct URLs

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions