abit-cache
Version:
React cache library from scratch
252 lines (205 loc) • 7.41 kB
Markdown
# React Abit Cache 🚀
A powerful React caching library with features like optimistic updates, cache invalidation, and more.
## Features
- 🕒 Data caching
- ♻️ Automatic revalidation on focus, reconnect, or interval
- ⚡ Optimistic updates for mutations
- 🧩 Suspense mode support
- 🔍 Deep comparison for efficient updates
- 🗑️ Cache invalidation by key or pattern matching
- 🔄 Retry mechanism for failed requests
- 📦 Lightweight and tree-shakable
## Installation
```bash
npm install abit-cache
# or
yarn add abit-cache
```
### Quick Start
1. Wrap your app with CacheProvider
```tsx
import { CacheProvider } from 'abit-cache';
function App() {
return (
<CacheProvider
value={{
staleTime: 1000 * 60 * 5, // 5 minutes
isRevalidateOnFocus: true,
}}
>
<YourApp />
</CacheProvider>
);
}
```
2. Use useQuery for data fetching
```tsx
import { useQuery } from 'abit-cache';
function UserProfile({ userId }) {
const { data, error, isLoading } = useQuery(
['user', userId],
async ([, id]) => {
const response = await fetch(`/api/users/${id}`);
return response.json();
},
{
staleTime: 1000 * 30, // 30 seconds
onSuccess: (data) => console.log('User loaded:', data),
},
);
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
}
return <div>{data.name}</div>;
```
3. Use useMutation for data updates
```tsx
import { useMutation } from 'abit-cache';
function UpdateProfile() {
const { mutate, isMutating } = useMutation(
'update-profile',
async (variables) => {
const response = await fetch('/api/profile', {
method: 'POST',
body: JSON.stringify(variables),
});
return response.json();
},
{
optimisticData: (currentData) => ({
...currentData,
...variables,
}),
},
);
const handleSubmit = (data) => {
mutate(data, {
onSuccess: () => alert('Profile updated!'),
});
};
return (
<form onSubmit={handleSubmit}>
<button type="submit" disabled={isMutating}>
{isMutating ? 'Saving...' : 'Save'}
</button>
</form>
);
}
```
### API Reference
#### CacheProvider
| Prop | Type | Description |
| ----- | ------------ | ----------------------------------- |
| value | TCacheConfig | Configuration options for the cache |
### useQuery
```ts
const {
data,
error,
isLoading,
revalidate,
invalidate,
invalidateMatching,
clear,
} = useQuery<TData>(key, fetcher, options);
```
### Parameters:
| Parameter | Type | Description |
| --------- | ------------------------------- | --------------------------------------------- |
| `key` | `string` \| `array` \| `object` | Unique key for the query |
| `fetcher` | `function` | Function that returns a Promise with the data |
| `options` | `object` (optional) | Configuration object |
### Options:
| Option | Type | Default | Description |
| ------------------------- | ---------- | -------------- | ------------------------------------ |
| `isEnabled` | `boolean` | `true` | Whether the query should execute |
| `isSuspense` | `boolean` | `false` | Enable Suspense mode |
| `staleTime` | `number` | `0` | Time until data is considered stale |
| `isRevalidateIfStale` | `boolean` | `true` | Auto-revalidate when stale |
| `isRevalidateOnFocus` | `boolean` | `false` | Revalidate when window regains focus |
| `isRevalidateOnReconnect` | `boolean` | `false` | Revalidate when network reconnects |
| `isKeepPreviousData` | `boolean` | `false` | Keep previous data while loading |
| `shouldRetryOnError` | `boolean` | `true` | Retry on error |
| `errorRetryInterval` | `number` | `5000` | Delay between retries (ms) |
| `errorRetryCount` | `number` | `3` | Max retry attempts |
| `dedupingInterval` | `number` | `2000` | Dedupe simultaneous requests (ms) |
| `focusThrottleInterval` | `number` | `5000` | Throttle focus revalidation (ms) |
| `onSuccess` | `function` | `-` | Callback on successful fetch |
| `onError` | `function` | `-` | Callback on error |
| `onErrorRetry` | `function` | `-` | Custom error retry handler |
| `isDeepEqual` | `function` | `shallowEqual` | Custom equality function |
### useMutation
```ts
const {
isMutating,
error,
data,
mutate,
invalidate,
invalidateMatching,
clear,
} = useMutation<TData, TVariables>(key, fetcher, options);
```
### Parameters
| Parameter | Type | Description |
| --------- | ------------------- | ----------------------------------------------------- |
| `key` | `string` | Unique key for the mutation |
| `fetcher` | `function` | Function that returns a Promise with the updated data |
| `options` | `object` (optional) | Configuration object (optional) |
### Options
| Option | Type | Default | Description |
| ------------------- | -------------------- | ------- | ----------------------------------- |
| `isRevalidate` | `boolean` | `true` | Revalidate after mutation |
| `isRollbackOnError` | `boolean` | `true` | Rollback optimistic update on error |
| `optimisticData` | `Data` \| `function` | `-` | Data to show immediately |
| `onSuccess` | `function` | `-` | Callback on successful mutation |
| `onError` | `function` | `-` | Callback on error |
| `onSettled` | `function` | `-` | Callback after mutation completes |
```ts
const { invalidateMatching } = useQuery(...);
// Delete all cache entries starting with 'user'
invalidateMatching('^user');
```
### Suspense Mode
```tsx
function UserProfile({ userId }) {
const { data } = useQuery(['user', userId], fetchUser, { isSuspense: true });
return <div>{data.name}</div>;
}
function App() {
return (
<Suspense fallback={<div>Loading user...</div>}>
<UserProfile userId="123" />
</Suspense>
);
}
```
### Global Configuration
```tsx
<CacheProvider
value={{
staleTime: 1000 * 60 * 10, // 10 minutes
isRevalidateOnFocus: true,
isRevalidateOnReconnect: true,
errorRetryCount: 5,
onError: (err) => trackError(err),
}}
>
<App />
</CacheProvider>
```
> TypeScript Support
> The library is fully typed with TypeScript. All hooks and types are exported:
```ts
import {
useQuery,
useMutation,
CacheProvider,
type TCacheOptions,
type TMutateOptions,
} from 'abit-cache';
```
Contributing
Contributions are welcome! Please open an issue or PR on GitHub.
### License
MIT