Package Exports
- use-fetch-smart
- use-fetch-smart/dist/index.js
- use-fetch-smart/dist/index.mjs
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (use-fetch-smart) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
use-fetch-smart
A smart React data-fetching library with caching, TTL, retry logic, token auto-refresh, and simple mutation hooks.
✨ Why use-fetch-smart?
Fetching data in React apps often ends up with repetitive boilerplate: loading states, error handling, caching, token refresh logic, retry logic, etc.
use-fetch-smart is designed to replace that boilerplate with a clean, declarative interface and handle many of the common patterns for you.
Key benefits:
- Smart GET hook with caching + Time-to-Live (TTL) expiry
- Mutation hooks (POST / PUT / DELETE) with minimal setup
- Automatic retry logic (for network failures or 5xx responses)
- Automatic token refresh when a 401 occurs, and request replay
- Single global provider to configure your fetch-layer (base URL, token, retry limits)
- Devtools panel to inspect cache, TTL, retry counts, etc
- TypeScript first: full typing support out of the box
In short: stop re-writing loading/error/spinner logic, stop manually managing cache/invalidations, stop writing token refresh logic over and over. Let the library handle the data layer; you focus on your UI and domain logic.
🚀 Installation
npm install use-fetch-smart
# or
yarn add use-fetch-smart🧩 Provider Setup
Wrap your React app (or the high-level section of it) with the FetchSmartProvider to configure the global data‐fetching environment. Example:
import React from 'react';
import { FetchSmartProvider, FetchSmartDevtools } from 'use-fetch-smart';
const refreshToken = async () => {
// Your logic to request a new token when current one expires (401).
return await fetch('/auth/refresh')
.then(r => r.json())
.then(x => x.token)
.catch(() => null);
};
const AppWrapper = () => (
<FetchSmartProvider
config={{
baseURL: 'https://api.example.com',
token: 'initial-token-if-known',
refreshToken, // function to call on 401
retryLimit: 3, // global retry limit for failed requests
// you may add other axios-style config if supported
}}
>
<YourApp />
<FetchSmartDevtools />
</FetchSmartProvider>
);
export default AppWrapper;What this config does:
baseURL: the base URL for your API endpointstoken: initial token (if you already have one in memory/storage)refreshToken: a function returning a new token (ornullif refresh fails) — this will be automatically used when a request gets a 401retryLimit: number of retry attempts for network/server errors
Once the provider is set up, all hooks (useGetSmart, usePostSmart, etc.) will automatically use this configured instance.
📊 Fetching Data — useGetSmart
import { useGetSmart } from 'use-fetch-smart';
const Users = () => {
const { data, loading, error, refetch } = useGetSmart<User[]>('/users', {
cacheTimeMs: 2 * 60 * 1000,
persist:true
});
---
# use-fetch-smart
> A lightweight, TypeScript-first React data-fetching layer with built-in caching (memory + optional IndexedDB), TTL, retries, and automatic token refresh.
[](https://www.npmjs.com/package/use-fetch-smart) [](https://github.com/zaidshaikh2811/use-fetch-smart)
---
## Install
```bash
npm install use-fetch-smart
# or
yarn add use-fetch-smartThis package uses axios and includes optional IndexedDB persistence via idb-keyval for larger or persistent caches.
Quick Start
Wrap your app with FetchSmartProvider to configure baseURL, token handling, and retry behavior.
import React from 'react';
import { FetchSmartProvider, FetchSmartDevtools } from 'use-fetch-smart';
const refreshToken = async () => {
// Example: call your refresh endpoint and return the new token string or `null`.
const r = await fetch('/auth/refresh');
if (!r.ok) return null;
const json = await r.json();
return json.token;
};
export default function AppRoot() {
return (
<FetchSmartProvider config={{ baseURL: 'http://localhost:4000', retryLimit: 3, refreshToken }}>
<App />
<FetchSmartDevtools />
</FetchSmartProvider>
);
}What you get
useGetSmart— GET hook with instant cache reads, TTL and refetch.usePostSmart,usePutSmart,useDeleteSmart— simple mutation hooks with loading/error states.- Layered cache: fast in-memory cache plus optional persistent IndexedDB via
cacheDriver. - Automatic token refresh and request replay on 401 when a
refreshTokenfunction is provided. - Automatic retries for network errors and 5xx responses with backoff.
- Devtools component to inspect cache keys, TTL, and request history.
Hooks — quick examples
useGetSmart
import { useGetSmart } from 'use-fetch-smart';
function Users() {
const { data, loading, error, refetch } = useGetSmart('/users', { cacheTimeMs: 60_000, persist: false });
if (loading) return <div>Loading…</div>;
if (error) return <div>Error</div>;
return (
<div>
<button onClick={refetch}>Refresh</button>
<pre>{JSON.stringify(data, null, 2)}</pre>
</div>
);
}usePostSmart
import { usePostSmart } from 'use-fetch-smart';
function CreateUser() {
const { mutate, loading } = usePostSmart('/users');
return (
<button onClick={() => mutate({ name: 'Zaid' })} disabled={loading}>
{loading ? 'Saving…' : 'Create User'}
</button>
);
}Cache & Persistence
The library uses a layered cache:
memoryCache— fast in-memory store for instant readsindexedDBCache(viaidb-keyval) — optional persistence for larger or long-lived cachescacheDriver— unified API toget/set/deleteand to opt into persistence per entry (persist: true)
Use cacheTimeMs and persist options to control TTL and storage mode.
Example: store a GET response in IndexedDB for 10 minutes:
useGetSmart('/settings', { cacheTimeMs: 10 * 60_000, persist: true });Advanced usage & utilities
You can use lower-level utilities exported by the package for advanced scenarios:
import { cacheManager, axiosInstance } from 'use-fetch-smart';
// clear a specific cache key
cacheManager.clear('GET_/users');
// use the provided axios instance for non-hook requests
axiosInstance.get('/status');If you need to build a custom axios instance, the package exposes a createSmartAxios helper in the source files (see src/axiosInstance.ts).
Examples
This repo includes examples/ (Express backend + Vite React frontend) demonstrating provider setup and hooks. See examples/README.md for setup and run commands.
Optimizations & Best Practices
- Tune
cacheTimeMsper endpoint (short TTL for live lists, longer TTL for stable resources). - Use
persist: trueonly for expensive-to-fetch or important data (e.g., user preferences). - After mutations, call
refetch()on related queries or usecacheManager.clear()to invalidate. - Keep
retryLimitlow for mutation endpoints to avoid duplicate side effects; rely on server idempotency where possible. - Gate
FetchSmartDevtoolsbehind NODE_ENV !== 'production' during builds.
Troubleshooting
- Stale data: check TTL and whether you used
persist— callrefetch()or clear the key viacacheManager. - Repeated 401 refreshes: ensure your
refreshTokenreturnsnullon failure and your backend isn't returning 401 for all requests. - IndexedDB errors: browser may deny access in some environments;
cacheDriverfalls back to memory when IndexedDB fails.
Package & Version
- Current package version:
1.0.10(seepackage.json). - Type definitions included and
dist/is published via thefilesentry.
License
MIT © 2025
If you'd like, I can also:
- Add a short "Examples" section to the main
README.mdlinking toexamples/(I can apply this patch now). - Scaffold
examples/backendandexamples/frontendfiles into the repo and addnpmscripts to start them.
Suggested commit message:
docs(npm-readme): update README.npm.md to reflect cache/persistence and examples
- or integrate a custom invalidation logic: e.g., clear cache key manually using
cacheManager(if your library exposes it) - Example: after creating a new user, you might refetch
/users.
3. Token handling
Since the library handles auto‐refresh for 401s:
- Ensure your
refreshTokenlogic returns the new token (and persists it if you store it) - On refreshing token, subsequent calls will use the new token automatically
- Edge case: if refresh fails (returns null), you may want to redirect to login/logout.
4. Minimise over-fetching
- Use
skipor conditional fetches (if supported) when component shouldn’t fetch on mount (e.g., waiting user input) - Use
dependencies(if supported) to fetch only when necessary.
5. Server-side data and hydration (if e.g. using Next.js)
- If you’re using SSR/SSG, you may want to pre‐fetch data and hydrate the cache on the client. Check if your library supports that.
- While this library focuses on client‐side React, you may integrate with SSR setups by using initial cache values or disabling caching on initial load.
6. Bundling & tree-shaking
- Since this library is lightweight and TypeScript‐first, ensure your bundler (e.g., Webpack/Rollup) tree-shakes unused parts.
- Avoid importing full library if you only use one hook. (i.e.,
import { useGetSmart } from 'use-fetch-smart'). - Monitor bundle size (e.g., via
bundlephobia).
7. Error boundaries and global error handling
- While hooks provide
errorstate, you might use a global error boundary or React error boundary to catch unexpected exceptions. - Use logging (e.g., Sentry) for network/fetch errors to track in production.
📋 API Reference
FetchSmartProvider
Props:
config: { baseURL: string; token?: string; refreshToken?: () => Promise<string | null>; retryLimit?: number; /* plus any axios config like headers, timeout etc */ }- Children: your React tree
- Optionally include
<FetchSmartDevtools />as a child.
Hooks
useGetSmart<T>(url: string, options?: { cacheTimeMs?: number; skip?: boolean; dependencies?: any[]; /* other possible options */ }) => { data: T | undefined; loading: boolean; error: Error | null; refetch: () => Promise<void> }
usePostSmart<T, P>(url: string) => { mutate: (payload: P) => Promise<T>; loading: boolean; error: Error | null }
usePutSmart<T, P>(url: string) => { mutate: (payload: P) => Promise<T>; loading: boolean; error: Error | null }
useDeleteSmart<T>(url: string) => { mutate: () => Promise<T>; loading: boolean; error: Error | null }
Other exports
axiosInstance— underlying Axios instance (for advanced use)cacheManager— to programmatically inspect/clear cache (if supported)setGlobalToken— to set token globally outside hooks (if you update token elsewhere)
(Make sure to list any more utility methods your library provides.)
🧠 Why This Library Is Better
- Less boilerplate: you get data, loading, error, refetch in one line instead of writing your own state and effect every time.
- Caching built-in: You don’t need separate libraries for caching; TTL is built in and automatic.
- Retry logic: Out‐of‐the-box support for retrying failed requests, helping stability in flaky network conditions.
- Token refresh built-in: No need to write the same “if 401 then refresh token and retry” logic everywhere — the provider handles it.
- Single global config: You configure once (base URL, token, retry, etc) and all hooks inherit it.
- Devtools for visibility: Monitoring cache, TTL, retries, status codes gives you better insight during development.
- TypeScript support: Helps with correctness, developer experience and future maintenance.
- Focused & lightweight: Not a full state-management or data layer library (like React Query), but a simpler, focused solution for fetch + cache + retry + token. If you don’t need all features of a heavier library this may be a perfect fit.
🧪 Example Full Workflow
// index.tsx
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { FetchSmartProvider, FetchSmartDevtools } from 'use-fetch-smart';
const refreshToken = async () => {
const result = await fetch('/auth/refresh').then(r => r.json());
if (result.token) {
return result.token;
}
return null;
};
ReactDOM.render(
<FetchSmartProvider config={{ baseURL: 'https://api.myapp.com', token: localStorage.getItem('token') ?? undefined, refreshToken, retryLimit: 2 }}>
<App />
<FetchSmartDevtools />
</FetchSmartProvider>,
document.getElementById('root'),
);
// App.tsx
import React from 'react';
import { useGetSmart } from 'use-fetch-smart';
const Dashboard = () => {
const { data: users, loading, error, refetch } = useGetSmart<User[]>('/users', { cacheTimeMs: 5 * 60 * 1000 });
if (loading) return <div>Loading users …</div>;
if (error) return <div>Error loading users: {error.message}</div>;
return (
<div>
<h1>Users</h1>
<button onClick={refetch}>Refresh</button>
<ul>
{users?.map(u => <li key={u.id}>{u.name}</li>)}
</ul>
</div>
);
};
export default Dashboard;📦 Package Details & Stability
- Version: (update to latest)
- TypeScript definitions included
- MIT License
- Compatible with React 17+ (verify your supported versions)
- Lightweight bundle size (check on bundlephobia or similar)
👥 Contributing
If you’d like to contribute:
- Fork the repository
- Create a feature branch (
git checkout -b feature/my-feature) - Write tests where applicable
- Follow the code style in the repo
- Submit a pull request
- Issues and feature suggestions are welcome
📝 Changelog
Please refer to CHANGELOG.md in the repo for full version history and breaking changes.
🎉 Thank You
If you like use-fetch-smart, please star the GitHub repo — your support helps a lot ❤️
Happy fetching.
✅ Checklist for You
- Update version number and npm badge if needed
- Add links/badges for npm, bundle size, CI, license
- If there are additional options for hooks (e.g.,
skip,dependenciesetc), document them clearly - Provide example images or gifs (if you have) for cache hits, retry logic, token refresh, devtools
- Provide a section for migration (if you are replacing an older version)
- Ensure the README is published with the package (npm will show it)