@lecxa/shipstation-react-query
v1.0.0
Published
React Query hooks for ShipStation API v2 - Type-safe hooks with automatic caching and invalidation
Maintainers
Readme
@lecxa/shipstation-react-query
React Query hooks for ShipStation API v2 - Type-safe hooks with automatic caching and invalidation.
Features
- ✅ Full API Coverage - Hooks for all ShipStation API v2 endpoints
- 🔒 Type-Safe - Complete TypeScript definitions
- ⚡ Automatic Caching - Powered by TanStack Query
- 🔄 Auto-Refetch - Smart invalidation and background updates
- 📄 Pagination Support - Built-in infinite query hooks
- 🎯 Optimistic Updates - Instant UI feedback
Installation
npm install @lecxa/shipstation-react-query @tanstack/react-query
# or
pnpm add @lecxa/shipstation-react-query @tanstack/react-query
# or
yarn add @lecxa/shipstation-react-query @tanstack/react-queryPeer Dependencies
@tanstack/react-query^5.0.0react>=18
Quick Start
1. Setup Query Client
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 60 * 1000, // 1 minute
},
},
});
function App() {
return (
<QueryClientProvider client={queryClient}>
<YourApp />
</QueryClientProvider>
);
}2. Use Hooks
import {
useListShipments,
useCreateLabel,
useCalculateRates,
} from '@lecxa/shipstation-react-query';
function ShipmentsPage() {
// Query hook - automatic caching and refetching
const { data, isLoading, error } = useListShipments({
page: 1,
page_size: 50,
});
// Mutation hook - for creating/updating data
const createLabel = useCreateLabel();
const handleCreateLabel = async () => {
try {
const result = await createLabel.mutateAsync({
shipment: {
ship_to: { /* ... */ },
ship_from: { /* ... */ },
packages: [{ weight: { value: 1.5, unit: 'pound' } }],
},
carrier_code: 'stamps_com',
service_code: 'usps_priority_mail',
});
console.log('Label created:', result.label_id);
} catch (err) {
console.error('Failed to create label:', err);
}
};
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<div>
<button onClick={handleCreateLabel}>Create Label</button>
{data?.shipments.map(shipment => (
<div key={shipment.shipment_id}>{shipment.shipment_id}</div>
))}
</div>
);
}Infinite Queries
For paginated data, use infinite query hooks:
import { useListShipmentsInfinite } from '@lecxa/shipstation-react-query';
function InfiniteShipmentsList() {
const {
data,
fetchNextPage,
hasNextPage,
isFetchingNextPage,
} = useListShipmentsInfinite({
page_size: 50,
});
return (
<div>
{data?.pages.map((page, i) => (
<div key={i}>
{page.shipments?.map(shipment => (
<div key={shipment.shipment_id}>
{shipment.shipment_id}
</div>
))}
</div>
))}
{hasNextPage && (
<button
onClick={() => fetchNextPage()}
disabled={isFetchingNextPage}
>
{isFetchingNextPage ? 'Loading...' : 'Load More'}
</button>
)}
</div>
);
}Available Hooks
Query Hooks (GET requests)
useListBatches/useListBatchesInfiniteuseGetBatchByIduseListCarriersuseListShipments/useListShipmentsInfiniteuseGetShipmentByIduseCalculateRatesuseListLabels/useListLabelsInfiniteuseGetLabelById- And many more...
Mutation Hooks (POST/PUT/DELETE requests)
useCreateLabeluseCreateShipmentuseUpdateShipmentuseVoidLabeluseCreateBatchuseProcessBatch- And many more...
Authentication
Configure authentication using init options:
import { customFetcher } from '@lecxa/shipstation-sdk';
// Configure the fetcher with your token
const queryClient = new QueryClient({
defaultOptions: {
queries: {
queryFn: async ({ queryKey }) => {
return customFetcher(queryKey[0] as string, {
token: 'your-api-token',
});
},
},
},
});Cache Invalidation
Mutations automatically invalidate related queries:
const createLabel = useCreateLabel({
onSuccess: () => {
// Automatically invalidates and refetches label lists
queryClient.invalidateQueries({ queryKey: ['labels'] });
},
});TypeScript Support
All hooks are fully typed:
import type {
UseListShipmentsQueryResult,
UseCreateLabelMutationResult,
} from '@lecxa/shipstation-react-query';Advanced Usage
Custom Query Options
const { data } = useListShipments(
{ page: 1 },
{
// TanStack Query options
staleTime: 5 * 60 * 1000, // 5 minutes
refetchOnWindowFocus: false,
retry: 3,
}
);Optimistic Updates
const updateShipment = useUpdateShipment({
onMutate: async (newData) => {
// Cancel outgoing refetches
await queryClient.cancelQueries({ queryKey: ['shipments'] });
// Snapshot previous value
const previous = queryClient.getQueryData(['shipments']);
// Optimistically update
queryClient.setQueryData(['shipments'], (old) => ({
...old,
...newData,
}));
return { previous };
},
onError: (err, newData, context) => {
// Rollback on error
queryClient.setQueryData(['shipments'], context.previous);
},
});License
MIT © Lecxa
